First THREADED backport attempt, focusing on adding locks and making sure the API is threadsafe. Needs more work. Mor...

Original commit message from CVS:
First THREADED backport attempt, focusing on adding locks and
making sure the API is threadsafe. Needs more work. More docs
follow this week.
This commit is contained in:
Wim Taymans 2005-03-07 18:27:42 +00:00
parent d5e9b91e0a
commit c47dc4d853
89 changed files with 6018 additions and 3263 deletions

215
ChangeLog
View file

@ -1,3 +1,218 @@
2005-03-07 Wim Taymans <wim@fluendo.com>
* Makefile.am:
* configure.ac:
* docs/design/part-MT-refcounting.txt:
* docs/design/part-conventions.txt:
* docs/design/part-gstobject.txt:
* docs/design/part-relations.txt:
* examples/mixer/mixer.c: (main):
* examples/thread/thread.c: (eos), (main):
* gst/Makefile.am:
* gst/autoplug/gstsearchfuncs.c: (gst_autoplug_caps_intersect):
* gst/autoplug/gstspider.c: (gst_spider_identity_plug),
(gst_spider_plug_from_srcpad):
* gst/autoplug/gstspideridentity.c: (gst_spider_identity_getcaps),
(gst_spider_identity_change_state),
(gst_spider_identity_sink_loop_type_finding):
* gst/elements/gstfakesrc.c: (gst_fakesrc_loop):
* gst/elements/gstidentity.c: (gst_identity_init):
* gst/elements/gsttee.c: (gst_tee_init), (gst_tee_getcaps),
(gst_tee_link), (gst_tee_request_new_pad), (gst_tee_chain):
* gst/elements/gsttypefindelement.c: (free_entry):
* gst/gst.c:
* gst/gst.h:
* gst/gstbin.c: (gst_bin_init), (gst_bin_get_clock_func),
(gst_bin_set_clock_func), (gst_bin_auto_clock),
(gst_bin_set_index), (gst_bin_set_element_sched),
(gst_bin_unset_element_sched), (gst_bin_add_func), (gst_bin_add),
(gst_bin_remove_func), (gst_bin_remove), (iterate_child),
(gst_bin_iterate_elements), (iterate_child_recurse),
(gst_bin_iterate_recurse), (gst_bin_dispose), (compare_name),
(gst_bin_get_by_name), (gst_bin_get_by_name_recurse_up),
(compare_interface), (gst_bin_get_by_interface),
(gst_bin_iterate_all_by_interface), (gst_bin_iterate_func):
* gst/gstbin.h:
* gst/gstbuffer.c: (gst_buffer_get_type), (_gst_buffer_sub_free),
(gst_buffer_default_free), (gst_buffer_default_copy),
(gst_buffer_new), (gst_buffer_get_caps), (gst_buffer_set_caps),
(gst_buffer_create_sub):
* gst/gstbuffer.h:
* gst/gstcaps.c: (gst_caps_get_type), (gst_caps_new_empty),
(_gst_caps_free), (gst_caps_make_writable), (gst_caps_ref),
(gst_caps_unref), (gst_static_caps_get),
(gst_caps_remove_and_get_structure), (gst_caps_append),
(gst_caps_append_structure), (gst_caps_remove_structure),
(gst_caps_copy_nth), (gst_caps_set_simple),
(gst_caps_set_simple_valist), (gst_caps_is_fixed_foreach),
(gst_structure_is_equal_foreach), (gst_caps_is_subset),
(gst_caps_structure_intersect_field), (gst_caps_intersect),
(gst_caps_structure_subtract_field), (gst_caps_subtract),
(gst_caps_normalize_foreach), (gst_caps_compare_structures),
(gst_caps_structure_figure_out_union),
(gst_caps_switch_structures), (gst_caps_do_simplify),
(gst_caps_replace), (gst_caps_from_string),
(gst_caps_copy_conditional):
* gst/gstcaps.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_adjust_unlocked),
(gst_clock_get_time), (gst_clock_set_time_adjust),
(gst_clock_set_property), (gst_clock_get_property):
* gst/gstclock.h:
* gst/gstcompat.h:
* gst/gstcpu.c: (_gst_cpu_initialize_i386), (gst_cpu_get_flags):
* gst/gstdata.c: (gst_data_is_writable), (gst_data_copy_on_write):
* gst/gstdata.h:
* gst/gstelement.c: (gst_element_class_init), (gst_element_init),
(gst_element_requires_clock), (gst_element_provides_clock),
(gst_element_set_clock), (gst_element_clock_wait),
(gst_element_wait), (gst_element_set_time_delay),
(gst_element_is_indexable), (gst_element_add_pad),
(gst_element_add_ghost_pad), (gst_element_remove_pad),
(pad_compare_name), (gst_element_get_static_pad),
(gst_element_request_pad), (gst_element_get_request_pad),
(gst_element_get_pad), (iterate_pad), (gst_element_iterate_pads),
(gst_element_class_get_pad_template_list),
(gst_element_class_get_pad_template), (gst_element_error_func),
(gst_element_get_random_pad), (gst_element_get_event_masks),
(gst_element_send_event), (gst_element_seek),
(gst_element_get_query_types), (gst_element_query),
(gst_element_get_formats), (gst_element_convert),
(gst_element_is_locked_state), (gst_element_set_locked_state),
(gst_element_sync_state_with_parent), (gst_element_change_state),
(gst_element_finalize), (gst_element_yield),
(gst_element_interrupt), (gst_element_set_scheduler),
(gst_element_get_scheduler), (gst_element_set_loop_function):
* gst/gstelement.h:
* gst/gstevent.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/gstindex.c: (gst_index_gtype_resolver):
* gst/gstinfo.c:
* gst/gstinfo.h:
* gst/gstmemchunk.c: (gst_mem_chunk_alloc), (gst_mem_chunk_alloc0),
(gst_mem_chunk_free):
* gst/gstobject.c: (gst_object_class_init), (gst_object_init),
(gst_object_ref), (gst_object_unref), (gst_object_sink),
(gst_object_replace), (gst_object_dispose), (gst_object_finalize),
(gst_object_dispatch_properties_changed),
(gst_object_set_name_default), (gst_object_set_name),
(gst_object_get_name), (gst_object_set_name_prefix),
(gst_object_get_name_prefix), (gst_object_set_parent),
(gst_object_get_parent), (gst_object_unparent),
(gst_object_check_uniqueness), (gst_object_save_thyself),
(gst_object_restore_thyself), (gst_object_real_restore_thyself),
(gst_object_set_property), (gst_object_get_property),
(gst_object_get_path_string):
* gst/gstobject.h:
* gst/gstpad.c: (gst_pad_dispose), (gst_real_pad_class_init),
(gst_real_pad_init), (gst_real_pad_get_property),
(gst_pad_custom_new), (gst_pad_get_direction),
(gst_pad_set_active), (gst_pad_is_active),
(gst_pad_set_event_function), (gst_pad_is_linked),
(gst_pad_link_free), (gst_pad_link_intersect),
(gst_pad_link_fixate), (gst_pad_set_caps),
(gst_pad_try_set_caps_nonfixed), (gst_pad_set_pad_template),
(gst_pad_get_real_parent), (gst_pad_add_ghost_pad),
(gst_pad_remove_ghost_pad), (_gst_pad_default_fixate_foreach),
(gst_pad_link_unnegotiate), (gst_pad_proxy_fixate),
(gst_pad_get_caps), (gst_pad_peer_get_caps),
(gst_pad_get_pad_template_caps), (gst_pad_get_peer),
(gst_pad_realize), (gst_pad_get_allowed_caps),
(gst_real_pad_dispose), (gst_real_pad_finalize),
(gst_pad_collectv), (gst_pad_collect_valist),
(gst_pad_template_dispose), (gst_pad_template_new),
(gst_pad_get_internal_links):
* gst/gstpad.h:
* gst/gstpipeline.c: (gst_pipeline_dispose),
(gst_pipeline_change_state):
* gst/gstpipeline.h:
* gst/gstplugin.c:
* 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_link_sink), (gst_queue_link_src):
* gst/gstscheduler.c: (gst_scheduler_add_element),
(gst_scheduler_factory_create):
* gst/gststructure.c: (gst_structure_set_parent_refcount),
(gst_structure_free), (gst_structure_set_name),
(gst_structure_id_set_value), (gst_structure_set_value),
(gst_structure_set_valist), (gst_structure_remove_field),
(gst_structure_remove_fields),
(gst_structure_remove_fields_valist),
(gst_structure_remove_all_fields), (gst_structure_foreach),
(gst_structure_map_in_place),
(gst_caps_structure_fixate_field_nearest_int),
(gst_caps_structure_fixate_field_nearest_double):
* gst/gststructure.h:
* 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_unlocked), (gst_system_clock_id_wait),
(gst_system_clock_id_wait_async), (gst_system_clock_id_unschedule):
* gst/gstsystemclock.h:
* gst/gsttag.c: (gst_tag_list_add_value_internal),
(gst_tag_list_copy_foreach), (structure_foreach_wrapper):
* gst/gsttaginterface.c:
* gst/gstthread.c: (gst_thread_dispose),
(gst_thread_release_children_locks), (gst_thread_change_state),
(gst_thread_main_loop):
* gst/gsttrashstack.h:
* gst/gsttypefind.c: (gst_type_find_factory_dispose):
* gst/gsttypes.h:
* gst/gstutils.c: (gst_element_get_compatible_pad_template),
(gst_element_request_pad), (gst_element_get_pad_from_template),
(gst_element_request_compatible_pad),
(gst_element_get_compatible_pad_filtered),
(gst_element_get_compatible_pad), (gst_element_state_get_name),
(gst_element_link_pads_filtered), (gst_element_link_filtered),
(gst_element_link_many), (gst_element_link),
(gst_element_link_pads), (gst_element_unlink_pads),
(gst_element_unlink_many), (gst_element_unlink),
(gst_pad_can_link_filtered), (gst_pad_can_link),
(gst_pad_use_fixed_caps), (gst_pad_get_fixed_caps_func),
(gst_object_default_error), (gst_bin_add_many),
(gst_bin_remove_many), (gst_element_populate_std_props),
(gst_element_class_install_std_props), (gst_buffer_merge),
(gst_buffer_stamp), (intersect_caps_func), (gst_pad_proxy_getcaps),
(link_fold_func), (gst_pad_proxy_setcaps):
* gst/gstutils.h:
* gst/gstvalue.c: (gst_value_deserialize_string):
* gst/parse/grammar.y:
* gst/schedulers/gstbasicscheduler.c:
(gst_basic_scheduler_cothreaded_chain),
(gst_basic_scheduler_chain_recursive_add),
(gst_basic_scheduler_pad_link):
* gst/schedulers/gstoptimalscheduler.c:
(get_group_schedule_function),
(gst_opt_scheduler_state_transition),
(gst_opt_scheduler_add_element), (element_get_reachables_func):
* libs/gst/bytestream/bytestream.c:
* libs/gst/dataprotocol/dataprotocol.c:
(gst_dp_header_from_buffer):
* po/nb.po:
* po/ru.po:
* tests/threadstate/threadstate2.c: (eos):
* tools/gst-compprep.c: (main):
* tools/gst-inspect.c: (print_field), (print_element_flag_info),
(print_pad_info), (print_children_info):
* tools/gst-launch.c: (idle_func), (main):
* tools/gst-md5sum.c: (idle_func), (main):
* tools/gst-xmlinspect.c: (print_element_info):
First THREADED backport attempt, focusing on adding locks and
making sure the API is threadsafe. Needs more work. More docs
follow this week.
2005-02-24 Andy Wingo <wingo@pobox.com>
* tests/bench-complexity.scm:

View file

@ -8,13 +8,23 @@ SUBDIRS_DOCS =
endif
if BUILD_TESTS
SUBDIRS_TESTS = tests testsuite
## SUBDIRS_TESTS = tests testsuite
## FIXME: write tests from scratch
SUBDIRS_TESTS =
if HAVE_CHECK
SUBDIRS_CHECK = check
else
SUBDIRS_CHECK =
endif
else
SUBDIRS_TESTS =
SUBDIRS_CHECK =
endif
if BUILD_EXAMPLES
SUBDIRS_EXAMPLES = examples
## FIXME: write examples from scratch
# SUBDIRS_EXAMPLES = examples
SUBDIRS_EXAMPLES =
else
SUBDIRS_EXAMPLES =
endif
@ -31,7 +41,9 @@ aclocal_DATA = gst-element-check-@GST_MAJORMINOR@.m4
SUBDIRS = \
include gst libs tools \
$(SUBDIRS_TESTS) $(SUBDIRS_EXAMPLES) \
$(SUBDIRS_CHECK) \
$(SUBDIRS_TESTS) \
$(SUBDIRS_EXAMPLES) \
pkgconfig po \
common \
$(SUBDIRS_DOCS)
@ -40,6 +52,7 @@ SUBDIRS = \
DIST_SUBDIRS = \
include libs gst \
tools \
check \
tests testsuite \
examples \
pkgconfig \

View file

@ -24,7 +24,7 @@ dnl - library source changed -> increment REVISION
dnl - interfaces added/removed/changed -> increment CURRENT, REVISION = 0
dnl - interfaces added -> increment AGE
dnl - interfaces removed -> AGE = 0
AS_LIBTOOL(GST, 5, 0, 4)
AS_LIBTOOL(GST, 6, 0, 0)
AM_PROG_LIBTOOL
AC_CONFIG_SRCDIR([gst/gst.c])
@ -314,6 +314,10 @@ AC_SUBST(POPT_LIBS)
dnl Check for ucontext.h
AC_CHECK_HEADER(ucontext.h, AC_DEFINE(HAVE_UCONTEXT_H, 1, [defined if we have ucontext.h]))
dnl check for "check", unit testing library/header
AM_PATH_CHECK(0.9.2, HAVE_CHECK=yes, HAVE_CHECK=no)
AM_CONDITIONAL(HAVE_CHECK, test "x$HAVE_CHECK" = "xyes")
dnl ######################################################################
dnl # Check command line parameters, and set shell variables accordingly #
dnl ######################################################################
@ -664,6 +668,7 @@ libs/gst/control/Makefile
libs/gst/dataprotocol/Makefile
libs/gst/getbits/Makefile
po/Makefile.in
check/Makefile
tests/Makefile
tests/bufspeed/Makefile
tests/instantiate/Makefile

View file

@ -0,0 +1,381 @@
Conventions for thread a safe API
---------------------------------
The GStreamer API is designed to be thread safe. This means that API functions
can be called from multiple threads at the same time. GStreamer internally uses
threads to perform the data passing and various asynchronous services such as
the clock can also use threads.
This design decision has implication for the usage of the API and the objects
which this document explains.
MT safety techniques
--------------------
Several design patterns are used to guarantee object consistency in GStreamer.
This is an overview of the methods used in various GStreamer subsystems.
Refcounting:
All shared objects have a refcount associated with them. Each reference
obtained to the object should increase the refcount and each reference lost
should decrease the refcount.
The refcounting is used to make sure that when another thread destroys the
object, the ones which still hold a reference to the object do not read from
invalid memory when accessing the object.
Refcounting is also used to ensure that mutable data structures are only
modified when they are owned by the calling code.
It is a requirement that when two threads have a handle on an object, the
refcount must be more than one. This means that when one thread passes an
object to another thread it must increase the refcount. This requirement makes
sure that one thread cannot suddenly dispose the object making the other
thread crash when it tries to access the pointer to invalid memory.
Shared data structures and writability:
All objects have a refcount associated with them. Each reference obtained to
the object should increase the refcount and each reference lost should
decrease the refcount.
Each thread having a refcount to the object can safely read from the object.
but modifications made to the object should be preceeded with a
_get_writable() function call. This function will check the refcount of the
object and if the object is referenced by more than one instance, a copy is
made of the object that is then by definition only referenced from the calling
thread. This new copy is then modifyable without being visible to other
refcount holders.
This technique is used for information objects that, once created, never
change their values. The lifetime of these objects is generally short, the
objects are usually simple and cheap to copy/create.
The advantage of this method is that no reader/writers locks are needed. all
threads can concurrently read but writes happen locally on a new copy. In most
cases _get_writable() can avoid a real copy because the calling method is the
only one holding a reference, wich makes read/writes very cheap.
The drawback is that sometimes 1 needless copy can be done. This would happen
when N threads call _get_writable() at the same time, all seeing that N
references are held on the object. In this case 1 copy too many will be done.
This is not a problem in any practical situation because the copy operation is
fast.
Mutable substructures:
Special techniques are necessary to ensure the consistency of compound shared
objects. As mentioned above, shared objects need to have a reference count of
1 if they are to be modified. Implicit in this assumption is that all parts of
the shared object belong only to the object. For example, a GstStructure in
one GstCaps object should not belong to any other GstCaps object. This
condition suggests a parent-child relationship: structures can only be added
to parent object if they do not already have a parent object.
In addition, these substructures must not be modified while more than one code
segment has a reference on the parent object. For example, if the user creates
a GstStructure, adds it to a GstCaps, and the GstCaps is then referenced by
other code segments, the GstStructure should then become immutable, so that
changes to that data structure do not affect other parts of the code. This
means that the child is only mutable when the parent's reference count is 1,
as well as when the child structure has no parent.
The general solution to this problem is to include a field in child structures
pointing to the parent's atomic reference count. When set to NULL, this
indicates that the child has no parent. Otherwise, procedures that modify the
child structure must check if the parent's refcount is 1, and otherwise must
cause an error to be signaled.
Note that this is an internal implementation detail; application or plugin
code that calls _get_writable() on an object is guaranteed to receive an
object of refcount 1, which must then be writable. The only trick is that a
pointer to a child structure of an object is only valid while the calling code
has a reference on the parent object, because the parent is the owner of the
child.
Object locking:
For objects that contain state information and generally have a longer
lifetime, object locking is used to update the information contained in the
object.
All readers and writers acquire the lock before accessing the object. Only one
thread is allowed access the protected structures at a time.
Object locking is used for all objects extending from GstObject such as
GstElement, GstPad.
Atomic operations
Atomic operations are operations that are performed as one consistent
operation even when executed by multiple threads. They do however not use the
conventional aproach of using mutexes to protect the critical section but rely
on CPU features and instructions.
The advantages are mostly speed related since there are no heavyweight locks
involved. Most of this instructions also do not cause a context switch in case
of concurrent access but use a retry mechanism or spinlocking.
Disadvantages are that each of these instructions usually cause a cache flush
on multi-CPU machines when two processors perform concurrent access.
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.
Objects
-------
* Locking involved:
- atomic operations for refcounting
- object locking
All objects should have a lock associated with them. This lock is used to keep
internal consistency when multiple threads call API function on the object.
For objects that extend the GStreamer base object class this lock can be
obtained with the macros GST_LOCK() and GST_UNLOCK(). For other object that do
not extend from the base GstObject class these macros can be different.
* refcounting
All new objects created have the FLOATING flag set. This means that the object
is not owned or managed yet by anybody other than the one holding a reference
to the object. The object in this state has a reference count of 1.
Various object methods can take ownership of another object, this means that
after calling a method on object A with an object B as an argument, the object
B is made sole property of object A. This means that after the method call you
are not allowed to access the object anymore unless you keep an extra
reference to the object. An example of such a method is the _bin_add() method.
As soon as this function is called in a Bin, the element passed as an argument
is owned by the bin and you are not allowed to access it anymore without
taking a _ref() before adding it to the bin. The reason being that after the
_bin_add() call disposing the bin also destroys the element.
Taking ownership of an object happens trough the process of "sinking" the
object. the _sink() method on an object will decrease the refcount of the
object if the FLOATING flag is set. The act of taking ownership of an object
is then performed as a _ref() followed by a _sink() call on the object.
The float/sink process is very useful when initializing elements that will
then be placed under control of a parent. The floating ref keeps the object
alive until it is parented, and once the object is parented you can forget
about it.
* parent-child relations
One can create parent-child relationships with the _object_set_parent()
method. This method refs and sinks the object and assigns its parent property
to that of the managing parent.
The child is said to have a weak link to the parent since the refcount of the
parent is not increased in this process. This means that if the parent is
disposed it has to unset itself as the parent of the object before disposing
itself, else the child object holds a parent pointer to invalid memory.
The responsibilites for an object that sinks other objects are summarised as:
- taking ownership of the object
- call _object_set_parent() to set itself as the object parent, this call
will _ref() and _sink() the object.
- keep reference to object in a datastructure such as a list or array.
- on dispose
- call _object_unparent() to reset the parent property and unref the
object.
- remove the object from the list.
* Properties
Most objects also expose state information with public properties in the
object. Two types of properties might exist: accessible with or without
holding the object lock. All properties should only be accessed with their
corresponding macros. The public object properties are marked in the .h files
with /*< public >*/. The public properties that require a lock to be held are
marked with /*< public >*/ /* with <lock_type> */, where <lock_type> can be
"LOCK" or "STATE_LOCK" or any other lock to mark the type(s) of lock to be
held.
Example:
in GstPad there is a public property "direction". It can be found in the
section marked as public and requiring the LOCK to be held. There exists
also a macro to access the property.
struct _GstRealPad {
...
/*< public >*/ /* with LOCK */
...
GstPadDirection direction;
...
};
#define GST_RPAD_DIRECTION(pad) (GST_REAL_PAD_CAST(pad)->direction)
Accessing the property is therefore allowed with the following code example:
GST_LOCK (pad);
direction = GST_RPAD_DIRECTION (pad);
GST_UNLOCK (pad);
* Property lifetime
All properties requiring a lock can change after releasing the associated
lock. This means that as long as you hold the lock, the state of the
object regarding the locked properties is consistent with the information
obtained. As soon as the lock is released, any values required from the
properties might not be valid anymore and can as best be described as a
snapshot of the state when the lock was held.
This means that all properties that require access beyond the scope of the
critial section should be copied or refcounted before releasing the lock.
Most object provide a _get_<property>() method to get a copy or refcounted
instance of the property value. The caller should not wory about any locks
but should unref/free the object after usage.
Example:
the following example correctly gets the peer pad of an element. It is
required to increase the refcount of the peer pad because as soon as the
lock is released, the peer could be unreffed and disposed, making the
pointer obtained in the critical section point to invalid memory.
GST_LOCK (pad);
peer = GST_RPAD_PEER (pad);
if (peer)
gst_object_ref (GST_OBJECT (peer));
GST_UNLOCK (pad);
... use peer ...
if (peer)
gst_object_unref (GST_OBJECT (peer));
Note that after releasing the lock the peer might not actually be the peer
anymore of the pad. If you need to be sure it is, you need to extend the
critical section to include the operations on the peer.
Example:
Accessing the name of an object makes a copy of the name. The caller of the
function should g_free() the name after usage.
GST_LOCK (object)
name = g_strdup (object->name);
GST_UNLOCK (object)
... use name ...
g_free (name);
* Accessor methods
For aplications it is encouraged to use the public methods of the object. Most
useful operations can be performed with the methods so it is seldom required
to access the public fields manually.
All accessor methods that return an object should increase the refcount of the
returned object. The caller should _unref() the object after usage. Each
method should state this refcounting policy in the documentation.
* Accessing lists
If the object property is a list, concurrent list iteration is needed to get
the contents of the list. GStreamer uses the cookie mechanism to mark the last
update of a list. The list and the cookie are protected by the same lock. Each
update to a list requires the following actions:
- acquire lock
- update list
- update cookie
- release lock
Updating the cookie is usually done by incrementing its value by one. Since
cookies use guint32 its wraparound is for all practical reasons is not a
problem.
Iterating a list can safely be done by surrounding the list iteration with a
lock/unlock of the lock.
In some cases it is not a good idea to hold the lock for a long time while
iterating the list. The state change code for a bin in GStreamer, for example,
has to iterate over each element and perform a blocking call on each of them
causing infinite bin locking. In this case the cookie can be used to iterate a
list.
Example:
The following algorithm iterates a list and reverses the updates in the
case a concurrent update was done to the list while iterating. The idea is
that whenever we reacquire the lock, we check for updates to the cookie to
decide if we are still iterating the right list.
GST_LOCK (lock);
/* grab list and cookie */
cookie = object->list_cookie;
list = object-list;
while (list) {
GstObject *item = GST_OBJECT (list->data);
/* need to ref the item before releasing the lock */
gst_object_ref (item);
GST_UNLOCK (lock);
... use/change item here...
/* release item here */
gst_object_unref (item);
GST_LOCK (lock);
if (cookie != object->list_cookie) {
/* handle rollback caused by concurrent modification
* of the list here */
...rollback changes to items...
/* grab new cookie and list */
cookie = object->list_cookie;
list = object->list;
}
else {
list = g_list_next (list);
}
}
GST_UNLOCK (lock);
* GstIterator
GstIterator provides an easier way of retrieving elements in a concurrent
list. The following code example is equivalent to the previous example.
Example:
it = _get_iterator(object);
while (!done) {
switch (gst_iterator_next (it, &item)) {
case GST_ITERATOR_OK:
... use/change item here...
/* release item here */
gst_object_unref (item);
break;
case GST_ITERATOR_RESYNC:
/* handle rollback caused by concurrent modification
* of the list here */
...rollback changes to items...
/* resync iterator to start again */
gst_iterator_resync (it);
break;
case GST_ITERATOR_DONE:
done = TRUE;
break;
}
}
gst_iterator_free (it);

View file

@ -16,7 +16,7 @@ Function names
--------------
Within the context of a given object, functions defined in that object's header and/or source file will have their
object-specific prefix stripped. For instance, gst_element_add_pad() would be referred to as simply _get_pad(). Note
object-specific prefix stripped. For instance, gst_element_add_pad() would be referred to as simply _add_pad(). Note
that the trailing parentheses should always be present, but sometimes may not be. A prefixing underscore (_) will
always tell you it's a function, however, regardless of the presence or absence of the trailing parentheses.
@ -25,7 +25,59 @@ always tell you it's a function, however, regardless of the presence or absence
Values and macros defined as enums and preprocessor macros will be referred to in all capitals, as per their
definition. This includes object flags and element states, as well as general enums. Examples are the states NULL,
READY, PLAYING, and PAUSED; the element flags DECOUPLED and USE_COTHREAD, and state return values SUCCESS, FAILURE, and
READY, PLAYING, and PAUSED; the element flags LOCKED_STATE , and state return values SUCCESS, FAILURE, and
ASYNC. Where there is a prefix, as in the element flags, this is usually dropped, and implied. Not however that
element flags should be cross-checked with the header, as there are currently two conventions in use: with and without
_FLAGS_ in the middle.
FIXME: check flags for consistency.
Drawing conventions
===================
When drawing pictures the folowing conventions apply:
objects
-------
Objects are drawn with a box like
+------+
| |
+------+
pointers
--------
a pointer to an object.
+-----+
*--->| |
+-----+
an invalid pointer, this is a pointer that should not be used.
*-//->
elements
--------
+----------+
| name |
sink src
+----------+
pad links
---------
-----+ +---
| |
src--sink
-----+ +---

View file

@ -1,42 +1,72 @@
GstObject
=========
The base class for the entire GStreamer hierarchy is the GstObject. It is currently a bit of a hack caused by the
fact that GStreamer is built on top of GtkObject. GObject should help, if it's designed properly. Currently the
capabilities provided by GstObject are quite underutilized, this will be fixed with a refactoring of the
object system and a code cleanup at some point in the future. If nothing else, it serves as an easy check to see if a
given object belongs to GStreamer.
The base class for the entire GStreamer hierarchy is the GstObject.
Parentage
---------
A pointer is available to store the current parent of the object. This one of the two fundamental requires for a
hierarchical system such as GStreamer (for the other, read up on GstBin). Three functions are provided: _set_parent(),
_get_parent(), and _unparent(). The third is required because there is an explicit check in _set_parent(): an object
must not already have a parent if you wish to set one. You must unparent the object first. This allows for new
additions later.
A pointer is available to store the current parent of the object. This is one
of the two fundamental requires for a hierarchical system such as GStreamer
(for the other, read up on GstBin). Three functions are provided:
_set_parent(), _get_parent(), and _unparent(). The third is required because
there is an explicit check in _set_parent(): an object must not already have a
parent if you wish to set one. You must unparent the object first. This
allows for new additions later.
- GstObject's that can be parented:
GstElement (inside a bin)
GstPad (inside an element)
Refcounting
-----------
- GObject refcount is not threadsafe.
GStreamer sets it to a constant value on each _ref/_unref()
and uses an atomic int "refcount" instead for threadsafe refcounting
This implies you should always use gst_object_ref() and gst_object_unref() !
A reference count is kept for the object. When this is fully utilized, it will enable generic destruction of objects
by simply reducing the reference count to zero. GObject should provide these capabilities, however.
Naming
------
- names of objects cannot be changed when they are parented
- names of objects should be unique across parent
- set_name() can fail because of this
- as can gst_element_add_pad()/gst_bin_add_element()
- gst_object_set_name() only changes the object's name
- objects also have a name_prefix that is used to prefix the object name
during debugging and identification
- there are object-specific set_name's() which also set the name_prefix
on the object. This is useful for debugging purposes to give the object
a more identifiable name. Typically a parent will call _set_name_prefix
on children, taking a lock on them to do so.
Locking
-------
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. Note that
this does *not* mean that no other thread can modify the object at the same time that the lock is held. It only means
that any two sections of code that obey the lock are guaranteed to not be running simultaneously.
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.
This lock will ideally be used for parentage and refcounting, which is reasonable, since they are the only possible
things to protect in the GstObject.
All members of the GstObject structure marked as
/*< public >*/ /* with LOCK */
are protected by this lock. These members can only be accessed for reading
or writing while the lock is held.
Note that this does *not* mean that no other thread can modify the object at
the same time that the lock is held. It only means that any two sections of
code that obey the lock are guaranteed to not be running simultaneously. "The
lock is voluntary and cooperative".
This lock will ideally be used for parentage and refcounting, which is
reasonable, since they are the only possible things to protect in the
GstObject.
Path Generation
---------------
FIXME: rethink this ?
Due to the base nature of the GstObject, it becomes the only reasonable place to put this particular function
(_get_path_string). It will generate a string describing the parent hierarchy of a given GstObject. Currently it is
forced to use several child-class-specific functions, because we do not properly use the base capabilities (parentage,
etc.) of GstObject properly.
Due to the base nature of the GstObject, it becomes the only reasonable place
to put this particular function (_get_path_string). It will generate a string
describing the parent hierarchy of a given GstObject. Currently it is forced
to use several child-class-specific functions, because we do not properly use
the base capabilities (parentage, etc.) of GstObject properly.

View file

@ -0,0 +1,487 @@
Object relation types
---------------------
1) parent-child relation
+---------+ +-------+
| parent | | child |
*--->| *----->| |
| F1|<-----* 1|
+---------+ +-------+
- properties
- parent has references to multiple children
- child has reference to parent
- reference fields protected with LOCK
- the reference held by each child to the parent is
NOT reflected in the refcount of the parent.
- the parent removes the floating flag of the child when taking
ownership.
- the application has valid reference to parent
- creation/destruction requires two unnested locks and 1 refcount.
- usage in GStreamer
GstBin -> GstElement
GstElement -> GstRealPad
- lifecycle
a) object creation
The application creates two object and holds a pointer
to them. The objects are initially FLOATING with a refcount
of 1.
+---------+ +-------+
*--->| parent | *--->| child |
| * | | |
| F1| | * F1|
+---------+ +-------+
b) establishing the parent-child relationship
The application then calls a method on the parent object to take
ownership of the child object. The parent performs the following
actions:
result = _set_parent (child, parent);
if (result) {
LOCK (parent);
ref_pointer = child;
.. update other data structures ..
UNLOCK (parent);
}
else {
.. child had parent ..
}
The _set_parent() method performs the following actions:
LOCK (child);
if (child->parent != NULL) {
UNLOCK (child);
return FALSE;
}
if (IS_FLOATING (child)) {
UNSET (child, FLOATING);
}
else {
_ref (child);
}
child->parent = parent;
UNLOCK (child);
_signal (PARENT_SET, child, parent);
return TRUE;
The function atomically checks if the child has no parent yet
and will set the parent if not. It will also sink the child, meaning
all floating references to the child are invalid now as it takes
over the refcount of the object.
Visually:
after _set_parent() returns TRUE:
+---------+ +-------+
*---->| parent | *-//->| child |
| * | | |
| F1|<-------------* 1|
+---------+ +-------+
after parent updates ref_pointer to child.
+---------+ +-------+
*---->| parent | *-//->| child |
| *--------->| |
| F1|<---------* 1|
+---------+ +-------+
- only one parent is able to _sink the same object because the
_set_parent() method is atomic.
- since only one parent is able to _set_parent() the object, only
one will add a reference to the object.
- since the parent can hold multiple references to children, we don't
need to lock the parent when locking the child. Many threads can
call _set_parent() on the children with the same parent, the parent
can then add all those to its lists.
Note: that the signal is emited before the parent has added the
element to its internal data structures. This is not a problem
since the parent usually has his own signal to inform the app that
the child was reffed. One possible solution would be to update the
internal structure first and then perform a rollback if the _set_parent()
failed. This is not a good solution as iterators might grab the
'half-added' child too soon.
c) using the parent-child relationship
- since the initial floating reference to the child object became
invalid after giving it to the parent, any reference to a child
has at least a refcount > 1.
- this means that unreffing a child object cannot decrease the refcount
to 0. In fact, only the parent can destroy and dispose the child
object.
- given a reference to the child object, the parent pointer is only
valid when holding the child LOCK. Indeed, after unlocking the child
LOCK, the parent can unparent the child or the parent could even become
disposed. To avoid the parent dispose problem, when obtaining the
parent pointer, if should be reffed before releasing the child LOCK.
I) getting a reference to the parent.
- a referece is held to the child, so it cannot be disposed.
LOCK (child);
parent = _ref (child->parent);
UNLOCK (child);
.. use parent ..
_unref (parent);
II) getting a reference to a child
- a reference to a child can be obtained by reffing it before
adding it to the parent or by querying the parent.
- when requesting a child from the parent, a reference is held to
the parent so it cannot be disposed. The parent will use its
internal data structures to locate the child element and will
return a reference to it with an incremented refcount. The
requester should _unref() the child after usage.
d) destroying the parent-child relationship
- only the parent can actively destroy the parent-child relationship
this typically happens when a method is called on the parent to release
ownership of the child.
- a child shall never remove itself from the parent.
- since calling a method on the parent with the child as an argument
requires the caller to obtain a valid reference to the child, the child
refcount is at least > 1.
- the parent will perform the folowing actions:
LOCK (parent);
if (ref_pointer == child) {
ref_pointer = NULL;
.. update other data structures ..
UNLOCK (parent);
_unparent (child);
}
else {
UNLOCK (parent);
.. not our child ..
}
The _unparent() method performs the following actions:
LOCK (child);
if (child->parent != NULL) {
child->parent = NULL;
UNLOCK (child);
_signal (PARENT_UNSET, child, parent);
_unref (child);
}
else {
UNLOCK (child);
}
Since the _unparent() method unrefs the child object, it is possible that
the child pointer is invalid after this function. If the parent wants to
perform other actions on the child (such as signal emmision) it should
_ref() the child first.
2) single-reffed relation
+---------+ +---------+
*--->| object1 | *--->| object2 |
| *--------->| |
| 1| | 2|
+---------+ +---------+
- properties
- one object has a reference to another
- reference field protected with LOCK
- the reference held by the object is reflected in the
refcount of the other object.
- typically the other object can be shared among multiple
other objects where each ref is counted for in the
refcount.
- no object has ownership of the other.
- either shared state or copy-on-write.
- creation/destruction requires one lock and one refcount.
- usage
GstRealPad -> GstCaps
GstBuffer -> GstCaps
GstEvent -> GstCaps
GstEvent -> GstObject
GstMessage -> GstCaps
GstMessage -> GstObject
- lifecycle
a) Two objects exist unlinked.
+---------+ +---------+
*--->| object1 | *--->| object2 |
| * | | |
| 1| | 1|
+---------+ +---------+
b) establishing the single-reffed relationship
The second object is attached to the first one using a method
on the first object. The second object is reffed and a pointer
is updated in the first object using the following algorithm:
LOCK (object1);
if (object1->pointer)
_unref (object1->pointer);
object1->pointer = _ref (object2);
UNLOCK (object1);
After releasing the lock on the first object is is not sure that
object2 is still reffed from object1.
+---------+ +---------+
*--->| object1 | *--->| object2 |
| *--------->| |
| 1| | 2|
+---------+ +---------+
c) using the single-reffed relationship
The only way to access object2 is by holding a ref to it or by
getting the reference from object1.
Reading the object pointed to by object1 can be done like this:
LOCK (object1);
object2 = object1->pointer;
_ref (object2);
UNLOCK (object1);
.. use object2 ...
_unref (object2);
Depending on the type of the object, modifications can be done either
with copy-on-write or directly into the object.
Copy on write can practically only be done like this:
LOCK (object1);
object2 = object1->pointer;
object2 = _copy_on_write (object2);
... make modifications to object2 ...
UNLOCK (object1);
Releasing the lock has only a very small window where the copy_on_write
actually does not perform a copy:
LOCK (object1);
object2 = object1->pointer;
_ref (object2);
UNLOCK (object1);
.. object2 now has at least 2 refcounts making the next
copy-on-write make a real copy, unless some other thread
writes another object2 to object1 here ...
object2 = _copy_on_write (object2);
.. make modifications to object2 ...
LOCK (object1);
if (object1->pointer != object2) {
if (object1->pointer)
_unref (object1->pointer);
object1->pointer = gst_object_ref (object2);
}
UNLOCK (object1);
d) destroying the single-reffed relationship
The folowing algorithm removes the single-reffed link between
object1 and object2.
LOCK (object1);
_unref (object1->pointer);
object1->pointer = NULL;
UNLOCK (object1);
Which yields the following initial state again:
+---------+ +---------+
*--->| object1 | *--->| object2 |
| * | | |
| 1| | 1|
+---------+ +---------+
3) unreffed relation
+---------+ +---------+
*--->| object1 | *--->| object2 |
| *--------->| |
| 1|<---------* 1|
+---------+ +---------+
- properties
- two objects have references to eachother
- both objects can only have 1 reference to another object.
- reference fields protected with LOCK
- the references held by each object are NOT reflected in the
refcount of the other object.
- no object has ownership of the other.
- typically each object is owned by a different parent.
- creation/destruction requires two nested locks and no refcounts.
- usage
- This type of link is used when the link is less important than
the existance of the objects, If one of the objects is disposed, so
is the link.
GstRealPad <-> GstRealPad (srcpad lock taken first)
- lifecycle
a) Two objects exist unlinked.
+---------+ +---------+
*--->| object1 | *--->| object2 |
| * | | |
| 1| | * 1|
+---------+ +---------+
b) establishing the unreffed relationship
Since we need to take two locks, the order in which these locks are
taken is very important or we might cause deadlocks. This lock order
must be defined for all unreffed relations. In these examples we always
lock object1 first and then object2.
LOCK (object1);
LOCK (object2);
object2->refpointer = object1;
object1->refpointer = object2;
UNLOCK (object2);
UNLOCK (object1);
c) using the unreffed relationship
Reading requires taking one of the locks and reading the corresponing
object. Again we need to ref the object before releasing the lock.
LOCK (object1);
object2 = _ref (object1->refpointer);
UNLOCK (object1);
.. use object2 ..
_unref (object2);
d) destroying the unreffed relationship
Because of the lock order we need to be careful when destroying this
Relation.
When only a reference to object1 is held:
LOCK (object1);
LOCK (object2);
object1->refpointer->refpointer = NULL;
object1->refpointer = NULL;
UNLOCK (object2);
UNLOCK (object1);
When only a reference to object2 is held we need to get a handle to the
other object fist so that we can lock it first. There is a window where
we need to release all locks and the relation could be invalid. To solve
this we check the relation after grabbing both locks and retry if the
relation changed.
retry:
LOCK (object2);
object1 = _ref (object2->refpointer);
UNLOCK (object2);
.. things can change here ..
LOCK (object1);
LOCK (object2);
if (object1 == object2->refpointer) {
/* relation unchanged */
object1->refpointer->refpointer = NULL;
object1->refpointer = NULL;
}
else {
/* relation changed.. retry */
UNLOCK (object2);
UNLOCK (object1);
_unref (object1);
goto retry;
}
UNLOCK (object2);
UNLOCK (object1);
_unref (object1);
When references are held to both objects. Note that it is not possible to
get references to both objects with the locks released since when the
references are taken and the locks are released, a concurrent update might
have changed the link, making the references not point to linked objects.
LOCK (object1);
LOCK (object2);
if (object1->refpointer == object2) {
object2->refpointer = NULL;
object1->refpointer = NULL;
}
else {
.. objects are not linked ..
}
UNLOCK (object2);
UNLOCK (object1);
4) double-reffed relation
+---------+ +---------+
*--->| object1 | *--->| object2 |
| *--------->| |
| 2|<---------* 2|
+---------+ +---------+
- properties
- two objects have references to eachother
- reference fields protected with LOCK
- the references held by each object are reflected in the
refcount of the other object.
- no object has ownership of the other.
- typically each object is owned by a different parent.
- creation/destruction requires two locks and two refcounts.
- usage
Not used in GStreamer.
- lifecycle

View file

@ -187,7 +187,7 @@ main (int argc, char *argv[])
gst_element_set_state (main_bin, GST_STATE_PLAYING);
/* write out the schedule */
gst_scheduler_show (GST_ELEMENT_SCHED (main_bin));
gst_scheduler_show (GST_ELEMENT_SCHEDULER (main_bin));
playing = TRUE;
j = 0;

View file

@ -1,6 +1,8 @@
#include <stdlib.h>
#include <gst/gst.h>
static GMainLoop *loop;
/* eos will be called when the src element has an end of stream */
void
eos (GstElement * element, gpointer data)
@ -12,7 +14,8 @@ eos (GstElement * element, gpointer data)
/* stop the bin */
gst_element_set_state (GST_ELEMENT (thread), GST_STATE_NULL);
gst_main_quit ();
g_main_loop_quit (loop);
g_main_loop_unref (loop);
}
int
@ -68,7 +71,7 @@ main (int argc, char *argv[])
/* start playing */
gst_element_set_state (GST_ELEMENT (thread), GST_STATE_PLAYING);
gst_main ();
loop = g_main_loop_new (NULL, FALSE);
gst_object_unref (GST_OBJECT (thread));

View file

@ -66,7 +66,7 @@ else
GST_URI_SRC = gsturi.c
endif
SUBDIRS = $(GST_PARSE_DIRS) $(GST_REGISTRY_DIRS) . autoplug elements schedulers $(GST_INDEX_DIRS)
SUBDIRS = $(GST_PARSE_DIRS) $(GST_REGISTRY_DIRS) . elements schedulers $(GST_INDEX_DIRS)
DIST_SUBDIRS = autoplug elements parse registries schedulers indexers
# make variables for all generated source and header files to make the
@ -98,6 +98,7 @@ libgstreamer_@GST_MAJORMINOR@_la_SOURCES = \
$(GST_INDEX_SRC) \
gstinfo.c \
gstinterface.c \
gstiterator.c \
gstmemchunk.c \
gstpad.c \
gstpipeline.c \
@ -171,6 +172,7 @@ gst_headers = \
gstindex.h \
gstinfo.h \
gstinterface.h \
gstiterator.h \
gstmacros.h \
gstmemchunk.h \
gstpad.h \

View file

@ -65,12 +65,12 @@ gst_autoplug_caps_intersect (const GstCaps * src, const GstCaps * sink)
/* if the caps can't link, there is no intersection */
if (gst_caps_is_empty (caps)) {
gst_caps_free (caps);
gst_caps_unref (caps);
return FALSE;
}
/* hurrah, we can link, now remove the intersection */
gst_caps_free (caps);
gst_caps_unref (caps);
return TRUE;
}

View file

@ -464,11 +464,11 @@ gst_spider_identity_plug (GstSpiderIdentity * ident)
GST_ELEMENT_ERROR (spider, STREAM, CODEC_NOT_FOUND,
(_("There is no element present to handle the stream's mime type %s."), mime), (NULL));
gst_caps_free (src_caps);
gst_caps_unref (src_caps);
return;
}
}
gst_caps_free (src_caps);
gst_caps_unref (src_caps);
}
/* get the direction of our ident */
@ -491,7 +491,7 @@ gst_spider_identity_plug (GstSpiderIdentity * ident)
}
/* now iterate all possible pads and link when needed */
padlist = gst_element_get_pad_list (GST_ELEMENT (spider));
padlist = GST_ELEMENT (spider)->pads;
for (; padlist; padlist = padlist->next) {
GstPad *otherpad;
GstSpiderIdentity *peer;
@ -697,8 +697,8 @@ gst_spider_plug_from_srcpad (GstSpiderConnection * conn, GstPad * srcpad)
caps1 = gst_pad_get_caps (srcpad);
caps2 = gst_pad_get_caps (conn->src->sink);
plugpath = gst_autoplug_sp (caps1, caps2, spider->factories);
gst_caps_free (caps1);
gst_caps_free (caps2);
gst_caps_unref (caps1);
gst_caps_unref (caps2);
/* prints out the path that was found for plugging */
/* g_print ("found path from %s to %s:\n", GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (conn->src));

View file

@ -289,7 +289,7 @@ gst_spider_identity_getcaps (GstPad * pad)
if (ident->caps) {
GstCaps *ret2 = gst_caps_intersect (ident->caps, ret);
gst_caps_free (ret);
gst_caps_unref (ret);
ret = ret2;
}
return ret;
@ -388,12 +388,12 @@ gst_spider_identity_change_state (GstElement * element)
gst_pad_get_caps ((GstPad *) GST_PAD_PEER (ident->sink));
if (gst_caps_is_any (caps) || gst_caps_is_empty (caps)) {
gst_spider_identity_start_type_finding (ident);
gst_caps_free (caps);
gst_caps_unref (caps);
break;
} else {
gst_spider_identity_plug (ident);
}
gst_caps_free (caps);
gst_caps_unref (caps);
}
/* autoplug on src */
if ((GST_RPAD_PEER (ident->src) != NULL)
@ -528,7 +528,7 @@ gst_spider_identity_sink_loop_type_finding (GstSpiderIdentity * ident)
if (!gst_caps_is_empty (find.caps) && !gst_caps_is_any (find.caps)) {
goto plug;
} else {
gst_caps_free (find.caps);
gst_caps_unref (find.caps);
find.caps = NULL;
}

View file

@ -887,7 +887,7 @@ gst_fakesrc_loop (GstElement * element)
src = GST_FAKESRC (element);
pads = gst_element_get_pad_list (element);
pads = element->pads;
while (pads) {
GstPad *pad = GST_PAD (pads->data);

View file

@ -203,14 +203,14 @@ gst_identity_init (GstIdentity * identity)
gst_element_add_pad (GST_ELEMENT (identity), identity->sinkpad);
gst_pad_set_chain_function (identity->sinkpad,
GST_DEBUG_FUNCPTR (gst_identity_chain));
gst_pad_set_link_function (identity->sinkpad, gst_pad_proxy_pad_link);
//gst_pad_set_link_function (identity->sinkpad, gst_pad_proxy_pad_link);
gst_pad_set_getcaps_function (identity->sinkpad, gst_pad_proxy_getcaps);
identity->srcpad =
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
"src");
gst_element_add_pad (GST_ELEMENT (identity), identity->srcpad);
gst_pad_set_link_function (identity->srcpad, gst_pad_proxy_pad_link);
//gst_pad_set_link_function (identity->srcpad, gst_pad_proxy_pad_link);
gst_pad_set_getcaps_function (identity->srcpad, gst_pad_proxy_getcaps);
identity->loop_based = DEFAULT_LOOP_BASED;

View file

@ -141,8 +141,7 @@ gst_tee_init (GstTee * tee)
"sink");
gst_element_add_pad (GST_ELEMENT (tee), tee->sinkpad);
gst_pad_set_chain_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_tee_chain));
gst_pad_set_link_function (tee->sinkpad,
GST_DEBUG_FUNCPTR (gst_pad_proxy_pad_link));
//gst_pad_set_link_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_pad_proxy_pad_link));
gst_pad_set_getcaps_function (tee->sinkpad,
GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
@ -169,16 +168,15 @@ gst_tee_getcaps (GstPad * _pad)
GstPad *pad;
const GList *pads;
for (pads = gst_element_get_pad_list (GST_ELEMENT (tee));
pads != NULL; pads = pads->next) {
for (pads = GST_ELEMENT (tee)->pads; pads != NULL; pads = pads->next) {
pad = GST_PAD (pads->data);
if (pad == _pad)
continue;
tmp = gst_pad_get_allowed_caps (pad);
res = gst_caps_intersect (caps, tmp);
gst_caps_free (tmp);
gst_caps_free (caps);
gst_caps_unref (tmp);
gst_caps_unref (caps);
caps = res;
}
@ -195,8 +193,7 @@ gst_tee_link (GstPad * _pad, const GstCaps * caps)
GST_DEBUG_OBJECT (tee, "Forwarding link to all other pads");
for (pads = gst_element_get_pad_list (GST_ELEMENT (tee));
pads != NULL; pads = pads->next) {
for (pads = GST_ELEMENT (tee)->pads; pads != NULL; pads = pads->next) {
pad = GST_PAD (pads->data);
if (pad == _pad)
continue;
@ -231,7 +228,7 @@ gst_tee_request_new_pad (GstElement * element, GstPadTemplate * templ,
tee = GST_TEE (element);
/* try names in order and find one that's not in use atm */
pads = gst_element_get_pad_list (element);
pads = element->pads;
name = NULL;
while (!name) {
@ -335,7 +332,7 @@ gst_tee_chain (GstPad * pad, GstData * _data)
gst_buffer_ref_by_count (buf, GST_ELEMENT (tee)->numsrcpads - 1);
pads = gst_element_get_pad_list (GST_ELEMENT (tee));
pads = GST_ELEMENT (tee)->pads;
while (pads) {
GstPad *outpad = GST_PAD (pads->data);

View file

@ -350,7 +350,7 @@ free_entry (TypeFindEntry * entry)
free_entry_buffers (entry);
if (entry->caps)
gst_caps_free (entry->caps);
gst_caps_unref (entry->caps);
g_free (entry);
}
static void

View file

@ -814,77 +814,6 @@ init_popt_callback (poptContext context, enum poptCallbackReason reason,
}
}
/**
* gst_use_threads:
* @use_threads: a #gboolean indicating whether threads should be used
*
* Does nothing anymore. GStreamer requires threads to be enabled at all times.
*
* Deprecated: This function is deprecated and should not be used in new code.
*/
void
gst_use_threads (gboolean use_threads)
{
}
/**
* gst_has_threads:
*
* Queries if GStreamer has threads enabled.
*
* Returns: %TRUE if threads are enabled.
* Deprecated: This function is deprecated and should not be used in new code.
*/
gboolean
gst_has_threads (void)
{
return TRUE;
}
static GSList *mainloops = NULL;
/**
* gst_main:
*
* Enters the main GStreamer processing loop.
*
* This function duplicates functionality in glib, and will be removed
* during the 0.9 development series.
*/
void
gst_main (void)
{
GMainLoop *loop;
loop = g_main_loop_new (NULL, FALSE);
mainloops = g_slist_prepend (mainloops, loop);
g_main_loop_run (loop);
}
/**
* gst_main_quit:
*
* Exits the main GStreamer processing loop.
*
* This function duplicates functionality in glib, and will be removed
* during the 0.9 development series.
*/
void
gst_main_quit (void)
{
if (!mainloops)
g_error ("Quit more loops than there are");
else {
GMainLoop *loop = mainloops->data;
mainloops = g_slist_delete_link (mainloops, mainloops);
g_main_loop_quit (loop);
g_main_loop_unref (loop);
}
}
/**
* gst_version:
* @major: pointer to a guint to store the major version number

View file

@ -42,6 +42,7 @@
#include <gst/gstindex.h>
#include <gst/gstinfo.h>
#include <gst/gstinterface.h>
#include <gst/gstiterator.h>
#include <gst/gstmarshal.h>
#include <gst/gstobject.h>
#include <gst/gstpad.h>
@ -95,14 +96,6 @@ gboolean gst_init_check_with_popt_table (int *argc, char **argv[],
const GstPoptOption * gst_init_get_popt_table (void);
#ifndef GST_DISABLE_DEPRECATED
void gst_use_threads (gboolean use_threads);
gboolean gst_has_threads (void);
#endif
void gst_main (void);
void gst_main_quit (void);
G_END_DECLS
#endif /* __GST_H__ */

View file

@ -1,7 +1,7 @@
/* GStreamer
*
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* 2004 Wim Taymans <wim@fluendo.com>
*
* gstbin.c: GstBin container object and support code
*
@ -19,6 +19,8 @@
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* MT safe.
*/
#include "gst_private.h"
@ -46,7 +48,7 @@ GST_DEBUG_CATEGORY_STATIC (bin_debug);
static GstElementDetails gst_bin_details = GST_ELEMENT_DETAILS ("Generic bin",
"Generic/Bin",
"Simple container object",
"Erik Walthinsen <omega@cse.ogi.edu>");
"Erik Walthinsen <omega@cse.ogi.edu>," "Wim Taymans <wim@fluendo.com>");
GType _gst_bin_type = 0;
@ -62,8 +64,8 @@ static GstElementStateReturn gst_bin_change_state_norecurse (GstBin * bin);
static void gst_bin_set_index (GstElement * element, GstIndex * index);
#endif
static void gst_bin_add_func (GstBin * bin, GstElement * element);
static void gst_bin_remove_func (GstBin * bin, GstElement * element);
static gboolean gst_bin_add_func (GstBin * bin, GstElement * element);
static gboolean gst_bin_remove_func (GstBin * bin, GstElement * element);
static void gst_bin_child_state_change_func (GstBin * bin,
GstElementState oldstate, GstElementState newstate, GstElement * child);
GstElementStateReturn gst_bin_set_state (GstElement * element,
@ -206,11 +208,9 @@ _gst_boolean_did_something_accumulator (GSignalInvocationHint * ihint,
static void
gst_bin_init (GstBin * bin)
{
/* in general, we prefer to use cothreads for most things */
GST_FLAG_SET (bin, GST_BIN_FLAG_PREFER_COTHREADS);
bin->numchildren = 0;
bin->children = NULL;
bin->children_cookie = 0;
}
/**
@ -230,8 +230,8 @@ gst_bin_new (const gchar * name)
static GstClock *
gst_bin_get_clock_func (GstElement * element)
{
if (GST_ELEMENT_SCHED (element))
return gst_scheduler_get_clock (GST_ELEMENT_SCHED (element));
if (GST_ELEMENT_SCHEDULER (element))
return gst_scheduler_get_clock (GST_ELEMENT_SCHEDULER (element));
return NULL;
}
@ -239,8 +239,8 @@ gst_bin_get_clock_func (GstElement * element)
static void
gst_bin_set_clock_func (GstElement * element, GstClock * clock)
{
if (GST_ELEMENT_SCHED (element))
gst_scheduler_use_clock (GST_ELEMENT_SCHED (element), clock);
if (GST_ELEMENT_SCHEDULER (element))
gst_scheduler_use_clock (GST_ELEMENT_SCHEDULER (element), clock);
}
/**
@ -287,19 +287,26 @@ gst_bin_auto_clock (GstBin * bin)
{
g_return_if_fail (GST_IS_BIN (bin));
if (GST_ELEMENT_SCHED (bin))
gst_scheduler_auto_clock (GST_ELEMENT_SCHED (bin));
if (GST_ELEMENT_SCHEDULER (bin))
gst_scheduler_auto_clock (GST_ELEMENT_SCHEDULER (bin));
}
#ifndef GST_DISABLE_INDEX
static void
gst_bin_set_index (GstElement * element, GstIndex * index)
{
GstBin *bin = GST_BIN (element);
GstBin *bin;
GList *children;
g_return_if_fail (GST_IS_BIN (bin));
bin = GST_BIN (element);
g_list_foreach (bin->children, (GFunc) gst_element_set_index, index);
GST_LOCK (bin);
for (children = bin->children; children; children = g_list_next (children)) {
GstElement *child = GST_ELEMENT (children->data);
gst_element_set_index (child, index);
}
GST_UNLOCK (bin);
}
#endif
@ -314,8 +321,8 @@ gst_bin_set_element_sched (GstElement * element, GstScheduler * sched)
if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) {
GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, element,
"child is already a manager, not resetting sched");
if (GST_ELEMENT_SCHED (element))
gst_scheduler_add_scheduler (sched, GST_ELEMENT_SCHED (element));
if (GST_ELEMENT_SCHEDULER (element))
gst_scheduler_add_scheduler (sched, GST_ELEMENT_SCHEDULER (element));
return;
}
@ -365,7 +372,7 @@ gst_bin_set_element_sched (GstElement * element, GstScheduler * sched)
static void
gst_bin_unset_element_sched (GstElement * element, GstScheduler * sched)
{
if (GST_ELEMENT_SCHED (element) == NULL) {
if (GST_ELEMENT_SCHEDULER (element) == NULL) {
GST_CAT_DEBUG (GST_CAT_SCHEDULING, "element \"%s\" has no scheduler",
GST_ELEMENT_NAME (element));
return;
@ -373,7 +380,7 @@ gst_bin_unset_element_sched (GstElement * element, GstScheduler * sched)
GST_CAT_DEBUG (GST_CAT_SCHEDULING,
"removing element \"%s\" from its sched %p", GST_ELEMENT_NAME (element),
GST_ELEMENT_SCHED (element));
GST_ELEMENT_SCHEDULER (element));
/* if it's actually a Bin */
if (GST_IS_BIN (element)) {
@ -382,7 +389,7 @@ gst_bin_unset_element_sched (GstElement * element, GstScheduler * sched)
GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, element,
"child is already a manager, not unsetting sched");
if (sched) {
gst_scheduler_remove_scheduler (sched, GST_ELEMENT_SCHED (element));
gst_scheduler_remove_scheduler (sched, GST_ELEMENT_SCHEDULER (element));
}
return;
}
@ -390,7 +397,7 @@ gst_bin_unset_element_sched (GstElement * element, GstScheduler * sched)
g_list_foreach (GST_BIN (element)->children,
(GFunc) gst_bin_unset_element_sched, sched);
gst_scheduler_remove_element (GST_ELEMENT_SCHED (element), element);
gst_scheduler_remove_element (GST_ELEMENT_SCHEDULER (element), element);
} else {
/* otherwise, if it's just a regular old element */
GList *pads;
@ -423,87 +430,77 @@ gst_bin_unset_element_sched (GstElement * element, GstScheduler * sched)
}
}
gst_scheduler_remove_element (GST_ELEMENT_SCHED (element), element);
gst_scheduler_remove_element (GST_ELEMENT_SCHEDULER (element), element);
}
}
/**
* gst_bin_add_many:
* @bin: the bin to add the elements to
* @element_1: the first element to add to the bin
* @...: additional elements to add to the bin
*
* Adds a NULL-terminated list of elements to a bin. This function is
* equivalent to calling #gst_bin_add() for each member of the list.
/* add an element to this bin
*
* MT safe
*/
void
gst_bin_add_many (GstBin * bin, GstElement * element_1, ...)
{
va_list args;
g_return_if_fail (GST_IS_BIN (bin));
g_return_if_fail (GST_IS_ELEMENT (element_1));
va_start (args, element_1);
while (element_1) {
gst_bin_add (bin, element_1);
element_1 = va_arg (args, GstElement *);
}
va_end (args);
}
static void
static gboolean
gst_bin_add_func (GstBin * bin, GstElement * element)
{
gint state_idx = 0;
GstElementState state;
GstScheduler *sched;
gchar *elem_name;
/* the element must not already have a parent */
g_return_if_fail (GST_ELEMENT_PARENT (element) == NULL);
/* we obviously can't add ourself to ourself */
if (G_UNLIKELY (GST_ELEMENT_CAST (element) == GST_ELEMENT_CAST (bin)))
goto adding_itself;
/* then check to see if the element's name is already taken in the bin */
if (gst_object_check_uniqueness (bin->children,
GST_ELEMENT_NAME (element)) == FALSE) {
g_warning ("Name %s is not unique in bin %s, not adding\n",
GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (bin));
return;
}
/* get the element name to make sure it is unique in this bin, FIXME, another
* thread can change the name after the unlock. */
GST_LOCK (element);
elem_name = g_strdup (GST_ELEMENT_NAME (element));
GST_UNLOCK (element);
if (GST_STATE (element) > GST_STATE (bin)) {
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
"setting state to receive element \"%s\"", GST_OBJECT_NAME (element));
gst_element_set_state ((GstElement *) bin, GST_STATE (element));
}
GST_LOCK (bin);
/* then check to see if the element's name is already taken in the bin,
* we can safely take the lock here. This check is probably bogus because
* you can safely change the element name after adding it to the bin. */
if (G_UNLIKELY (gst_object_check_uniqueness (bin->children,
elem_name) == FALSE))
goto duplicate_name;
/* set the element's parent and add the element to the bin's list of children */
gst_object_set_parent (GST_OBJECT (element), GST_OBJECT (bin));
if (G_UNLIKELY (!gst_object_set_parent (GST_OBJECT (element),
GST_OBJECT (bin))))
goto had_parent;
bin->children = g_list_append (bin->children, element);
bin->children = g_list_prepend (bin->children, element);
bin->numchildren++;
bin->children_cookie++;
/* bump our internal state counter */
state = GST_STATE (element);
while ((state >>= 1) != 0)
state_idx++;
bin->child_states[state_idx]++;
gst_element_set_scheduler (element, GST_ELEMENT_SCHEDULER (bin));
/* now we have to deal with manager stuff
* we can only do this if there's a scheduler:
* if we're not a manager, and aren't attached to anything, we have no sched (yet) */
sched = GST_ELEMENT_SCHED (bin);
if (sched) {
gst_bin_set_element_sched (element, sched);
}
GST_UNLOCK (bin);
GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, bin, "added element \"%s\"",
GST_OBJECT_NAME (element));
elem_name);
g_free (elem_name);
g_signal_emit (G_OBJECT (bin), gst_bin_signals[ELEMENT_ADDED], 0, element);
return TRUE;
/* ERROR handling here */
adding_itself:
GST_LOCK (bin);
g_warning ("Cannot add bin %s to itself", GST_ELEMENT_NAME (bin));
GST_UNLOCK (bin);
return FALSE;
duplicate_name:
g_warning ("Name %s is not unique in bin %s, not adding",
elem_name, GST_ELEMENT_NAME (bin));
GST_UNLOCK (bin);
g_free (elem_name);
return FALSE;
had_parent:
g_warning ("Element %s already has parent", elem_name);
GST_UNLOCK (bin);
g_free (elem_name);
return FALSE;
}
/**
@ -513,85 +510,86 @@ gst_bin_add_func (GstBin * bin, GstElement * element)
*
* Adds the given element to the bin. Sets the element's parent, and thus
* takes ownership of the element. An element can only be added to one bin.
*
* Returns: TRUE if the element could be added, FALSE on wrong parameters or
* the bin does not want to accept the element.
*
* MT safe.
*/
void
gboolean
gst_bin_add (GstBin * bin, GstElement * element)
{
GstBinClass *bclass;
gboolean result;
g_return_if_fail (GST_IS_BIN (bin));
g_return_if_fail (GST_IS_ELEMENT (element));
GST_CAT_INFO_OBJECT (GST_CAT_PARENTAGE, bin, "adding element \"%s\"",
GST_OBJECT_NAME (element));
g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
bclass = GST_BIN_GET_CLASS (bin);
if (bclass->add_element) {
bclass->add_element (bin, element);
} else {
GST_ELEMENT_ERROR (bin, CORE, FAILED, (NULL),
("cannot add element %s to bin %s",
GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (bin)));
}
if (G_UNLIKELY (bclass->add_element == NULL))
goto no_function;
GST_CAT_DEBUG (GST_CAT_PARENTAGE, "adding element %s to bin %s",
GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (bin));
result = bclass->add_element (bin, element);
return result;
no_function:
g_warning ("adding elements to bin %s is not supported",
GST_ELEMENT_NAME (bin));
return FALSE;
}
static void
/* remove an element from the bin
*
* MT safe
*/
static gboolean
gst_bin_remove_func (GstBin * bin, GstElement * element)
{
gint state_idx = 0;
GstElementState state;
gchar *elem_name;
/* the element must have its parent set to the current bin */
g_return_if_fail (GST_ELEMENT_PARENT (element) == (GstObject *) bin);
/* grab element name so we can print it */
GST_LOCK (element);
elem_name = g_strdup (GST_ELEMENT_NAME (element));
GST_UNLOCK (element);
GST_LOCK (bin);
/* the element must be in the bin's list of children */
if (g_list_find (bin->children, element) == NULL) {
g_warning ("no element \"%s\" in bin \"%s\"\n", GST_ELEMENT_NAME (element),
GST_ELEMENT_NAME (bin));
return;
}
/* remove this element from the list of managed elements */
gst_bin_unset_element_sched (element, GST_ELEMENT_SCHED (bin));
/* if it is still iterating, make it stop */
gst_element_release_locks (element);
if (G_UNLIKELY (g_list_find (bin->children, element) == NULL))
goto not_in_bin;
/* now remove the element from the list of elements */
bin->children = g_list_remove (bin->children, element);
bin->numchildren--;
/* bump our internal state counter */
state = GST_STATE (element);
while ((state >>= 1) != 0)
state_idx++;
bin->child_states[state_idx]--;
bin->children_cookie++;
GST_UNLOCK (bin);
GST_CAT_INFO_OBJECT (GST_CAT_PARENTAGE, bin, "removed child \"%s\"",
GST_OBJECT_NAME (element));
elem_name);
g_free (elem_name);
/* ref as we're going to emit a signal */
gst_element_set_scheduler (element, NULL);
/* we ref here because after the _unparent() the element can be disposed
* and we still need it to fire a signal. */
gst_object_ref (GST_OBJECT (element));
gst_object_unparent (GST_OBJECT (element));
/* if we're down to zero children, force state to NULL */
while (bin->numchildren == 0 && GST_ELEMENT_SCHED (bin) != NULL &&
GST_STATE (bin) > GST_STATE_NULL) {
GstElementState next = GST_STATE (bin) >> 1;
GST_STATE_PENDING (bin) = next;
gst_bin_change_state_norecurse (bin);
if (!GST_STATE (bin) == next) {
g_warning ("bin %s failed state change to %d", GST_ELEMENT_NAME (bin),
next);
break;
}
}
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));
return TRUE;
not_in_bin:
g_warning ("Element %s is not in bin %s", elem_name, GST_ELEMENT_NAME (bin));
GST_UNLOCK (bin);
g_free (elem_name);
return FALSE;
}
/**
@ -605,55 +603,132 @@ gst_bin_remove_func (GstBin * bin, GstElement * element)
* will be freed in the process of removing it from the bin. If you
* want the element to still exist after removing, you need to call
* #gst_object_ref before removing it from the bin.
*
* Returns: TRUE if the element could be removed, FALSE on wrong parameters or
* the bin does not want to remove the element.
*
* MT safe.
*/
void
gboolean
gst_bin_remove (GstBin * bin, GstElement * element)
{
GstBinClass *bclass;
gboolean result;
GST_CAT_DEBUG (GST_CAT_PARENTAGE, "[%s]: trying to remove child %s",
GST_ELEMENT_NAME (bin), GST_ELEMENT_NAME (element));
g_return_if_fail (GST_IS_BIN (bin));
g_return_if_fail (GST_IS_ELEMENT (element));
g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
bclass = GST_BIN_GET_CLASS (bin);
if (bclass->remove_element) {
bclass->remove_element (bin, element);
} else {
g_warning ("cannot remove elements from bin %s\n", GST_ELEMENT_NAME (bin));
}
if (G_UNLIKELY (bclass->remove_element == NULL))
goto no_function;
GST_CAT_DEBUG (GST_CAT_PARENTAGE, "removing element %s from bin %s",
GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (bin));
result = bclass->remove_element (bin, element);
return result;
no_function:
g_warning ("removing elements from bin %s is not supported",
GST_ELEMENT_NAME (bin));
return FALSE;
}
static GstIteratorItem
iterate_child (GstIterator * it, GstElement * child)
{
gst_object_ref (GST_OBJECT (child));
return GST_ITERATOR_ITEM_PASS;
}
/**
* gst_bin_remove_many:
* @bin: the bin to remove the elements from
* @element_1: the first element to remove from the bin
* @...: NULL-terminated list of elements to remove from the bin
*
* Remove a list of elements from a bin. This function is equivalent
* to calling #gst_bin_remove with each member of the list.
* gst_bin_iterate_elements:
* @bin: #Gstbin to iterate the elements of
*
* Get an iterator for the elements in this bin.
* Each element will have its refcount increased, so unref
* after usage.
*
* Returns: a #GstIterator of #GstElements. gst_iterator_free after
* use. returns NULL when passing bad parameters.
*
* MT safe.
*/
void
gst_bin_remove_many (GstBin * bin, GstElement * element_1, ...)
GstIterator *
gst_bin_iterate_elements (GstBin * bin)
{
va_list args;
GstIterator *result;
g_return_if_fail (GST_IS_BIN (bin));
g_return_if_fail (GST_IS_ELEMENT (element_1));
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
va_start (args, element_1);
GST_LOCK (bin);
/* add ref because the iterator refs the bin. When the iterator
* is freed it will unref the bin again using the provided dispose
* function. */
gst_object_ref (GST_OBJECT (bin));
result = gst_iterator_new_list (GST_GET_LOCK (bin),
&bin->children_cookie,
&bin->children,
bin,
(GstIteratorItemFunction) iterate_child,
(GstIteratorDisposeFunction) gst_object_unref);
GST_UNLOCK (bin);
while (element_1) {
gst_bin_remove (bin, element_1);
element_1 = va_arg (args, GstElement *);
}
va_end (args);
return result;
}
static GstIteratorItem
iterate_child_recurse (GstIterator * it, GstElement * child)
{
gst_object_ref (GST_OBJECT (child));
if (GST_IS_BIN (child)) {
GstIterator *other = gst_bin_iterate_recurse (GST_BIN (child));
gst_iterator_push (it, other);
}
return GST_ITERATOR_ITEM_PASS;
}
/**
* gst_bin_iterate_recurse:
* @bin: #Gstbin to iterate the elements of
*
* Get an iterator for the elements in this bin.
* Each element will have its refcount increased, so unref
* after usage. This iterator recurses into GstBin children.
*
* Returns: a #GstIterator of #GstElements. gst_iterator_free after
* use. returns NULL when passing bad parameters.
*
* MT safe.
*/
GstIterator *
gst_bin_iterate_recurse (GstBin * bin)
{
GstIterator *result;
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
GST_LOCK (bin);
/* add ref because the iterator refs the bin. When the iterator
* is freed it will unref the bin again using the provided dispose
* function. */
gst_object_ref (GST_OBJECT (bin));
result = gst_iterator_new_list (GST_GET_LOCK (bin),
&bin->children_cookie,
&bin->children,
bin,
(GstIteratorItemFunction) iterate_child_recurse,
(GstIteratorDisposeFunction) gst_object_unref);
GST_UNLOCK (bin);
return result;
return NULL;
}
/**
* gst_bin_child_state_change:
* @bin: #GstBin with the child
@ -942,54 +1017,61 @@ gst_bin_dispose (GObject * object)
GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, object, "dispose");
gst_element_set_state (GST_ELEMENT (object), GST_STATE_NULL);
/* ref to not hit 0 again */
gst_object_ref (GST_OBJECT (object));
while (bin->children) {
gst_bin_remove (bin, GST_ELEMENT (bin->children->data));
}
GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, object, "dispose no children");
g_assert (bin->children == NULL);
g_assert (bin->numchildren == 0);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static gint
compare_name (GstElement * element, const gchar * name)
{
gint eq;
GST_LOCK (element);
eq = strcmp (GST_ELEMENT_NAME (element), name) == 0;
GST_UNLOCK (element);
if (eq != 0) {
gst_object_unref (GST_OBJECT (element));
}
return eq;
}
/**
* gst_bin_get_by_name:
* @bin: #Gstbin to search
* @name: the element name to search for
*
* Get the element with the given name from this bin.
* Get the element with the given name from this bin. This
* function recurses into subbins.
*
* Returns: the element with the given name
* Returns: the element with the given name. Returns NULL if the
* element is not found or when bad parameters were given. Unref after
* usage.
*
* MT safe.
*/
GstElement *
gst_bin_get_by_name (GstBin * bin, const gchar * name)
{
GList *children;
GstElement *child;
GstIterator *children;
GstIterator *result;
g_return_val_if_fail (bin != NULL, NULL);
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
g_return_val_if_fail (name != NULL, NULL);
GST_CAT_INFO (GST_CAT_PARENTAGE, "[%s]: looking up child element %s",
GST_ELEMENT_NAME (bin), name);
children = gst_bin_iterate_recurse (bin);
result = gst_iterator_find_custom (children,
(GCompareFunc) compare_name, (gpointer) name);
children = bin->children;
while (children) {
child = GST_ELEMENT (children->data);
if (!strcmp (GST_OBJECT_NAME (child), name))
return child;
if (GST_IS_BIN (child)) {
GstElement *res = gst_bin_get_by_name (GST_BIN (child), name);
if (res)
return res;
}
children = g_list_next (children);
}
return NULL;
return GST_ELEMENT_CAST (result);
}
/**
@ -1000,45 +1082,49 @@ gst_bin_get_by_name (GstBin * bin, const gchar * name)
* Get the element with the given name from this bin. If the
* element is not found, a recursion is performed on the parent bin.
*
* Returns: the element with the given name
* Returns: the element with the given name or NULL when the element
* was not found or bad parameters were given. Unref after usage.
*
* MT safe.
*/
GstElement *
gst_bin_get_by_name_recurse_up (GstBin * bin, const gchar * name)
{
GstElement *result = NULL;
GstObject *parent;
GstElement *result;
g_return_val_if_fail (bin != NULL, NULL);
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
g_return_val_if_fail (name != NULL, NULL);
result = gst_bin_get_by_name (bin, name);
if (!result) {
parent = gst_object_get_parent (GST_OBJECT (bin));
GstObject *parent;
parent = gst_object_get_parent (GST_OBJECT_CAST (bin));
if (parent && GST_IS_BIN (parent)) {
result = gst_bin_get_by_name_recurse_up (GST_BIN (parent), name);
result = gst_bin_get_by_name_recurse_up (GST_BIN_CAST (parent), name);
}
gst_object_unref (parent);
}
return result;
}
/**
* gst_bin_get_list:
* @bin: #Gstbin to get the list from
*
* Get the list of elements in this bin.
*
* Returns: a GList of elements
*/
const GList *
gst_bin_get_list (GstBin * bin)
static gint
compare_interface (GstElement * element, gpointer interface)
{
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
gint ret;
return bin->children;
if (G_TYPE_CHECK_INSTANCE_TYPE (element, GPOINTER_TO_INT (interface))) {
ret = 0;
} else {
/* we did not find the element, need to release the ref
* added by the iterator */
gst_object_unref (GST_OBJECT (element));
ret = 1;
}
return ret;
}
/**
@ -1050,33 +1136,26 @@ gst_bin_get_list (GstBin * bin)
* interface. If such an element is found, it returns the element. You can
* cast this element to the given interface afterwards.
* If you want all elements that implement the interface, use
* gst_bin_get_all_by_interface(). The function recurses bins inside bins.
* gst_bin_iterate_all_by_interface(). The function recurses bins inside bins.
*
* Returns: An element inside the bin implementing the interface.
* Returns: An element inside the bin implementing the interface. Unref after
* usage.
*
* MT safe.
*/
GstElement *
gst_bin_get_by_interface (GstBin * bin, GType interface)
{
GList *walk;
GstIterator *children;
GstIterator *result;
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
g_return_val_if_fail (G_TYPE_IS_INTERFACE (interface), NULL);
walk = bin->children;
while (walk) {
if (G_TYPE_CHECK_INSTANCE_TYPE (walk->data, interface))
return GST_ELEMENT (walk->data);
if (GST_IS_BIN (walk->data)) {
GstElement *ret;
children = gst_bin_iterate_recurse (bin);
result = gst_iterator_find_custom (children, (GCompareFunc) compare_interface,
GINT_TO_POINTER (interface));
ret = gst_bin_get_by_interface (GST_BIN (walk->data), interface);
if (ret)
return ret;
}
walk = g_list_next (walk);
}
return NULL;
return GST_ELEMENT_CAST (result);
}
/**
@ -1086,34 +1165,25 @@ gst_bin_get_by_interface (GstBin * bin, GType interface)
*
* Looks for all elements inside the bin that implements the given
* interface. You can safely cast all returned elements to the given interface.
* The function recurses bins inside bins. You need to free the list using
* g_list_free() after use.
* The function recurses bins inside bins. The iterator will return a series
* of #GstElement that should be unreffed after usage.
*
* Returns: An iterator for the elements inside the bin implementing the interface.
*
* Returns: An element inside the bin implementing the interface.
*/
GList *
gst_bin_get_all_by_interface (GstBin * bin, GType interface)
GstIterator *
gst_bin_iterate_all_by_interface (GstBin * bin, GType interface)
{
GList *walk, *ret = NULL;
GstIterator *children;
GstIterator *result;
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
g_return_val_if_fail (G_TYPE_IS_INTERFACE (interface), NULL);
walk = bin->children;
while (walk) {
if (G_TYPE_CHECK_INSTANCE_TYPE (walk->data, interface)) {
GST_DEBUG_OBJECT (bin, "element %s implements requested interface",
GST_ELEMENT_NAME (GST_ELEMENT (walk->data)));
ret = g_list_prepend (ret, walk->data);
}
if (GST_IS_BIN (walk->data)) {
ret = g_list_concat (ret,
gst_bin_get_all_by_interface (GST_BIN (walk->data), interface));
}
walk = g_list_next (walk);
}
children = gst_bin_iterate_recurse (bin);
result = gst_iterator_filter (children, (GCompareFunc) compare_interface,
GINT_TO_POINTER (interface));
return ret;
return result;
}
/**
@ -1235,7 +1305,7 @@ static GStaticRecMutex iterate_lock = G_STATIC_REC_MUTEX_INIT;
static gboolean
gst_bin_iterate_func (GstBin * bin)
{
GstScheduler *sched = GST_ELEMENT_SCHED (bin);
GstScheduler *sched = GST_ELEMENT_SCHEDULER (bin);
g_static_rec_mutex_unlock (&iterate_lock);

View file

@ -25,6 +25,7 @@
#define __GST_BIN_H__
#include <gst/gstelement.h>
#include <gst/gstiterator.h>
G_BEGIN_DECLS
@ -36,6 +37,7 @@ GST_EXPORT GType _gst_bin_type;
#define GST_BIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_BIN, GstBinClass))
#define GST_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_BIN, GstBin))
#define GST_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_BIN, GstBinClass))
#define GST_BIN_CAST(obj) ((GstBin*)(obj))
/**
* GstBinFlags:
@ -58,45 +60,58 @@ GST_EXPORT GType _gst_bin_type;
* and (un)set using GST_FLAG_SET () and GST_FLAG_UNSET ().
*/
typedef enum {
GST_BIN_FLAG_MANAGER = GST_ELEMENT_FLAG_LAST,
GST_BIN_FLAG_FIXED_CLOCK = GST_ELEMENT_FLAG_LAST,
GST_BIN_FLAG_MANAGER,
GST_BIN_SELF_SCHEDULABLE,
GST_BIN_FLAG_PREFER_COTHREADS,
GST_BIN_FLAG_FIXED_CLOCK,
GST_BIN_STATE_LOCKED,
/* padding */
GST_BIN_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 5
} GstBinFlags;
/*typedef struct _GstBin GstBin; */
/*typedef struct _GstBinClass GstBinClass; */
#define GST_BIN_NUMCHILDREN(bin) (GST_BIN_CAST(bin)->numchildren);
#define GST_BIN_CHILDREN(bin) (GST_BIN_CAST(bin)->children);
#define GST_BIN_CHILDREN_COOKIE(bin) (GST_BIN_CAST(bin)->children_cookie);
struct _GstBin {
GstElement element;
/* our children */
/*< public >*/ /* with LOCK */
/* our children, subclass are supposed to update these
* fields to reflect their state with _iterate_*() */
gint numchildren;
GList *children;
guint32 children_cookie;
GstElementState child_states[GST_NUM_STATES];
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
struct _GstBinClass {
GstElementClass parent_class;
/* vtable */
void (*add_element) (GstBin *bin, GstElement *element);
void (*remove_element) (GstBin *bin, GstElement *element);
void (*child_state_change) (GstBin *bin, GstElementState oldstate,
GstElementState newstate, GstElement *element);
/*< public >*/
/* run a full iteration of operation */
gboolean (*iterate) (GstBin *bin);
void (*child_state_change) (GstBin *bin, GstElementState oldstate,
GstElementState newstate, GstElement *element);
/* signals */
void (*element_added) (GstBin *bin, GstElement *child);
void (*element_removed) (GstBin *bin, GstElement *child);
/*< protected >*/
/* vtable */
gboolean (*add_element) (GstBin *bin, GstElement *element);
gboolean (*remove_element) (GstBin *bin, GstElement *element);
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
@ -104,25 +119,24 @@ GType gst_bin_get_type (void);
GstElement* gst_bin_new (const gchar *name);
/* add and remove elements from the bin */
void gst_bin_add (GstBin *bin, GstElement *element);
void gst_bin_add_many (GstBin *bin, GstElement *element_1, ...);
void gst_bin_remove (GstBin *bin, GstElement *element);
void gst_bin_remove_many (GstBin *bin, GstElement *element_1, ...);
gboolean gst_bin_add (GstBin *bin, GstElement *element);
gboolean gst_bin_remove (GstBin *bin, GstElement *element);
/* retrieve a single element or the list of children */
GstElement* gst_bin_get_by_name (GstBin *bin, const gchar *name);
GstElement* gst_bin_get_by_name_recurse_up (GstBin *bin, const gchar *name);
G_CONST_RETURN GList*
gst_bin_get_list (GstBin *bin);
GstElement* gst_bin_get_by_interface (GstBin *bin, GType interface);
GList * gst_bin_get_all_by_interface (GstBin *bin, GType interface);
/* retrieve a single child */
GstElement* gst_bin_get_by_name (GstBin *bin, const gchar *name);
GstElement* gst_bin_get_by_name_recurse_up (GstBin *bin, const gchar *name);
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);
gboolean gst_bin_iterate (GstBin *bin);
void gst_bin_use_clock (GstBin *bin, GstClock *clock);
GstClock* gst_bin_get_clock (GstBin *bin);
void gst_bin_auto_clock (GstBin *bin);
GstElementStateReturn gst_bin_sync_children_state (GstBin *bin);
/* internal */

View file

@ -28,7 +28,7 @@
#include "gstmemchunk.h"
#include "gstinfo.h"
GType _gst_buffer_type;
GType _gst_buffer_type = 0;
#ifndef GST_DISABLE_TRACE
/* #define GST_WITH_ALLOC_TRACE */
@ -60,7 +60,7 @@ _gst_buffer_initialize (void)
GType
gst_buffer_get_type (void)
{
if (_gst_buffer_type == 0) {
if (G_UNLIKELY (_gst_buffer_type == 0)) {
_gst_buffer_type = g_boxed_type_register_static ("GstBuffer",
(GBoxedCopyFunc) gst_data_copy, (GBoxedFreeFunc) gst_data_unref);
}
@ -74,6 +74,8 @@ _gst_buffer_sub_free (GstBuffer * buffer)
GST_BUFFER_DATA (buffer) = NULL;
GST_BUFFER_SIZE (buffer) = 0;
if (GST_BUFFER_CAPS (buffer))
gst_caps_unref (GST_BUFFER_CAPS (buffer));
_GST_DATA_DISPOSE (GST_DATA (buffer));
@ -86,6 +88,8 @@ _gst_buffer_sub_free (GstBuffer * buffer)
*
* Frees the memory associated with the buffer including the buffer data,
* unless the GST_BUFFER_DONTFREE flags was set or the buffer data is NULL.
*
* MT safe.
*/
void
gst_buffer_default_free (GstBuffer * buffer)
@ -102,39 +106,26 @@ gst_buffer_default_free (GstBuffer * buffer)
/* set to safe values */
GST_BUFFER_DATA (buffer) = NULL;
GST_BUFFER_SIZE (buffer) = 0;
if (GST_BUFFER_CAPS (buffer))
gst_caps_unref (GST_BUFFER_CAPS (buffer));
_GST_DATA_DISPOSE (GST_DATA (buffer));
gst_buffer_free_chunk (buffer);
}
/**
* gst_buffer_stamp:
* @dest: buffer to stamp
* @src: buffer to stamp from
*
* Copies additional information (timestamps and offsets) from one buffer to
* the other.
*/
void
gst_buffer_stamp (GstBuffer * dest, const GstBuffer * src)
{
g_return_if_fail (dest != NULL);
g_return_if_fail (src != NULL);
GST_BUFFER_TIMESTAMP (dest) = GST_BUFFER_TIMESTAMP (src);
GST_BUFFER_DURATION (dest) = GST_BUFFER_DURATION (src);
GST_BUFFER_OFFSET (dest) = GST_BUFFER_OFFSET (src);
GST_BUFFER_OFFSET_END (dest) = GST_BUFFER_OFFSET_END (src);
}
/**
* gst_buffer_default_copy:
* @buffer: a #GstBuffer to make a copy of.
*
* Make a full newly allocated copy of the given buffer, data and all.
* Note that the caps on the buffer are not copied but their refcount
* is increased.
*
* Returns: the new #GstBuffer.
*
* MT safe.
*/
GstBuffer *
gst_buffer_default_copy (GstBuffer * buffer)
@ -147,8 +138,10 @@ gst_buffer_default_copy (GstBuffer * buffer)
/* create a fresh new buffer */
copy = gst_buffer_alloc_chunk ();
GST_CAT_LOG (GST_CAT_BUFFER, "copy %p to %p", buffer, copy);
/* copy relevant flags */
flags = GST_DATA_FLAG_SHIFT (GST_BUFFER_KEY_UNIT) |
flags = GST_DATA_FLAG_SHIFT (GST_BUFFER_PREROLL) |
GST_DATA_FLAG_SHIFT (GST_BUFFER_IN_CAPS) |
GST_DATA_FLAG_SHIFT (GST_BUFFER_DELTA_UNIT);
flags = GST_BUFFER_FLAGS (buffer) & flags;
@ -165,9 +158,15 @@ gst_buffer_default_copy (GstBuffer * buffer)
GST_BUFFER_SIZE (copy) = GST_BUFFER_SIZE (buffer);
GST_BUFFER_MAXSIZE (copy) = GST_BUFFER_SIZE (buffer);
gst_buffer_stamp (copy, buffer);
GST_BUFFER_TIMESTAMP (copy) = GST_BUFFER_TIMESTAMP (buffer);
GST_BUFFER_DURATION (copy) = GST_BUFFER_DURATION (buffer);
GST_BUFFER_OFFSET (copy) = GST_BUFFER_OFFSET (buffer);
GST_BUFFER_OFFSET_END (copy) = GST_BUFFER_OFFSET_END (buffer);
GST_BUFFER_FREE_DATA_FUNC (copy) = NULL;
GST_BUFFER_PRIVATE (copy) = NULL;
if (GST_BUFFER_CAPS (buffer))
GST_BUFFER_CAPS (copy) = gst_caps_ref (GST_BUFFER_CAPS (buffer));
return copy;
}
@ -200,6 +199,8 @@ gst_buffer_free_chunk (GstBuffer * buffer)
* Creates a newly allocated buffer without any data.
*
* Returns: the new #GstBuffer.
*
* MT safe.
*/
GstBuffer *
gst_buffer_new (void)
@ -225,6 +226,7 @@ gst_buffer_new (void)
GST_BUFFER_OFFSET_END (newbuf) = GST_BUFFER_OFFSET_NONE;
GST_BUFFER_FREE_DATA_FUNC (newbuf) = NULL;
GST_BUFFER_PRIVATE (newbuf) = NULL;
GST_BUFFER_CAPS (newbuf) = NULL;
return newbuf;
}
@ -236,6 +238,8 @@ gst_buffer_new (void)
* Creates a newly allocated buffer with data of the given size.
*
* Returns: the new #GstBuffer.
*
* MT safe.
*/
GstBuffer *
gst_buffer_new_and_alloc (guint size)
@ -251,6 +255,62 @@ gst_buffer_new_and_alloc (guint size)
return newbuf;
}
/**
* gst_buffer_get_caps:
* @buffer: a #GstBuffer to get the caps of.
*
* Gets the media type of the buffer. This can be NULL if there
* is not media type attached to this buffer or when the media
* type is the same as the previous received buffer.
*
* This function does not increment the refcount of the caps. The
* caps pointer will therefore remain valid until the buffer is
* unreffed.
*
* Returns: the #GstCaps, or NULL if there was an error or there
* were no caps on this buffer.
*/
/* FIXME can we make this threadsafe without a lock on the buffer? */
GstCaps *
gst_buffer_get_caps (GstBuffer * buffer)
{
g_return_val_if_fail (buffer != NULL, NULL);
return GST_BUFFER_CAPS (buffer);
}
/**
* gst_buffer_set_caps:
* @buffer: a #GstBuffer to set the caps of.
* @caps: a #GstCaps to set.
*
* Sets the media type on the buffer. The caps' refcount will
* be increased and any previous caps on the buffer will be
* unreffed.
*/
/* FIXME can we make this threadsafe without a lock on the buffer? */
void
gst_buffer_set_caps (GstBuffer * buffer, GstCaps * caps)
{
GstCaps *oldcaps;
g_return_if_fail (buffer != NULL);
/* get old caps */
oldcaps = GST_BUFFER_CAPS (buffer);
/* ref new caps if any */
if (caps)
caps = gst_caps_ref (caps);
/* set caps */
GST_BUFFER_CAPS (buffer) = caps;
/* unref old caps if any */
if (oldcaps) {
gst_caps_unref (oldcaps);
}
}
/**
* gst_buffer_create_sub:
* @parent: a parent #GstBuffer to create a subbuffer from.
@ -264,6 +324,8 @@ gst_buffer_new_and_alloc (guint size)
* The duration field of the new buffer are set to GST_CLOCK_TIME_NONE.
*
* Returns: the new #GstBuffer, or NULL if there was an error.
*
* MT safe.
*/
GstBuffer *
gst_buffer_create_sub (GstBuffer * parent, guint offset, guint size)
@ -318,72 +380,14 @@ gst_buffer_create_sub (GstBuffer * parent, guint offset, guint size)
GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
GST_BUFFER_OFFSET_END (buffer) = GST_BUFFER_OFFSET_NONE;
if (GST_BUFFER_FLAG_IS_SET (parent, GST_BUFFER_DONTKEEP)) {
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_DONTKEEP);
}
if (GST_BUFFER_FLAG_IS_SET (parent, GST_BUFFER_READONLY)) {
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_READONLY);
}
GST_BUFFER_CAPS (buffer) = NULL;
return buffer;
}
/**
* gst_buffer_merge:
* @buf1: a first source #GstBuffer to merge.
* @buf2: the second source #GstBuffer to merge.
*
* Create a new buffer that is the concatenation of the two source
* buffers. The original source buffers will not be modified or
* unref'd.
*
* WARNING: Incorrect use of this function can lead to memory leaks.
* It is recommended to use gst_buffer_join() instead of this function.
*
* If the buffers point to contiguous areas of memory, the buffer
* is created without copying the data.
*
* Returns: the new #GstBuffer that's the concatenation of the source buffers.
*/
GstBuffer *
gst_buffer_merge (GstBuffer * buf1, GstBuffer * buf2)
{
GstBuffer *result;
/* we're just a specific case of the more general gst_buffer_span() */
result = gst_buffer_span (buf1, 0, buf2, buf1->size + buf2->size);
return result;
}
/**
* gst_buffer_join:
* @buf1: a first source #GstBuffer to merge.
* @buf2: the second source #GstBuffer to merge.
*
* Create a new buffer that is the concatenation of the two source
* buffers. The original buffers are unreferenced.
*
* If the buffers point to contiguous areas of memory, the buffer
* is created without copying the data.
*
* Returns: the new #GstBuffer that's the concatenation of the source buffers.
*/
GstBuffer *
gst_buffer_join (GstBuffer * buf1, GstBuffer * buf2)
{
GstBuffer *result;
/* we're just a specific case of the more general gst_buffer_span() */
result = gst_buffer_span (buf1, 0, buf2, buf1->size + buf2->size);
gst_buffer_unref (buf1);
gst_buffer_unref (buf2);
return result;
}
/**
* gst_buffer_is_span_fast:
* @buf1: a first source #GstBuffer.
@ -394,6 +398,8 @@ gst_buffer_join (GstBuffer * buf1, GstBuffer * buf2)
*
* Returns: TRUE if the buffers are contiguous,
* FALSE if a copy would be required.
*
* MT safe.
*/
gboolean
gst_buffer_is_span_fast (GstBuffer * buf1, GstBuffer * buf2)
@ -428,6 +434,8 @@ gst_buffer_is_span_fast (GstBuffer * buf1, GstBuffer * buf2)
* gst_buffer_is_span_fast() to determine if a memcpy will be needed.
*
* Returns: the new #GstBuffer that spans the two source buffers.
*
* MT safe.
*/
GstBuffer *
gst_buffer_span (GstBuffer * buf1, guint32 offset, GstBuffer * buf2,

View file

@ -26,6 +26,7 @@
#include <gst/gstdata.h>
#include <gst/gstclock.h>
#include <gst/gstcaps.h>
G_BEGIN_DECLS
@ -44,10 +45,8 @@ extern GType _gst_buffer_type;
#define GST_BUFFER_REFCOUNT(buf) GST_DATA_REFCOUNT(buf)
#define GST_BUFFER_REFCOUNT_VALUE(buf) GST_DATA_REFCOUNT_VALUE(buf)
#ifndef GST_DISABLE_DEPRECATED
#define GST_BUFFER_COPY_FUNC(buf) GST_DATA_COPY_FUNC(buf)
#define GST_BUFFER_FREE_FUNC(buf) GST_DATA_FREE_FUNC(buf)
#endif
#define GST_BUFFER_FLAGS(buf) GST_DATA_FLAGS(buf)
#define GST_BUFFER_FLAG_IS_SET(buf,flag) GST_DATA_FLAG_IS_SET (buf, flag)
@ -59,6 +58,7 @@ extern GType _gst_buffer_type;
#define GST_BUFFER_MAXSIZE(buf) (GST_BUFFER(buf)->maxsize)
#define GST_BUFFER_TIMESTAMP(buf) (GST_BUFFER(buf)->timestamp)
#define GST_BUFFER_DURATION(buf) (GST_BUFFER(buf)->duration)
#define GST_BUFFER_CAPS(buf) (GST_BUFFER(buf)->caps)
#define GST_BUFFER_OFFSET(buf) (GST_BUFFER(buf)->offset)
#define GST_BUFFER_OFFSET_END(buf) (GST_BUFFER(buf)->offset_end)
#define GST_BUFFER_FREE_DATA_FUNC(buf) (GST_BUFFER(buf)->free_data)
@ -87,6 +87,7 @@ extern GType _gst_buffer_type;
* @GST_BUFFER_DONTKEEP: the buffer should not be ref()ed, but copied instead
* before doing anything with it (for specially allocated hw buffers and such)
* @GST_BUFFER_IN_CAPS: the buffer has been added as a field in a #GstCaps.
* @GST_BUFFER_GAP: the buffer has been created to fill a gap in the stream.
* @GST_BUFFER_DELTA_UNIT: this unit cannot be decoded independently.
* Since 0.8.5
* @GST_BUFFER_FLAG_LAST: additional flags can be added starting from this flag.
@ -96,18 +97,20 @@ extern GType _gst_buffer_type;
typedef enum {
GST_BUFFER_READONLY = GST_DATA_READONLY,
GST_BUFFER_SUBBUFFER = GST_DATA_FLAG_LAST,
GST_BUFFER_ORIGINAL,
GST_BUFFER_DONTFREE,
GST_BUFFER_KEY_UNIT, /* deprecated, use reverse DELTA_UNIT */
GST_BUFFER_DONTKEEP, /* FIXME: is this deprecated ? there is no reference in gstreamer, gst-plugins */
GST_BUFFER_IN_CAPS,
GST_BUFFER_DELTA_UNIT, /* this unit depends on a previous unit */
GST_BUFFER_FLAG_LAST = GST_DATA_FLAG_LAST + 8
GST_BUFFER_ORIGINAL, /* original data, not copied, not currently used */
GST_BUFFER_DONTFREE, /* buffer data is managed by somebody else and cannot be freeed */
GST_BUFFER_PREROLL, /* sample should not be displayed */
GST_BUFFER_DISCONT, /* buffer is first after discontinuity in the stream */
GST_BUFFER_IN_CAPS, /* buffer is also part of caps */
GST_BUFFER_GAP, /* buffer has been created to fill a gap in the stream */
GST_BUFFER_DELTA_UNIT, /* can't be used as sync point in stream */
GST_BUFFER_FLAG_LAST = GST_DATA_FLAG_LAST + 8
} GstBufferFlag;
struct _GstBuffer {
GstData data_type;
/*< public >*/ /* with COW */
/* pointer to data and its size */
guint8 *data; /* pointer to buffer data */
guint size; /* size of buffer data */
@ -117,6 +120,9 @@ struct _GstBuffer {
GstClockTime timestamp;
GstClockTime duration;
/* the media type of this buffer */
GstCaps *caps;
/* media specific offset
* for video frames, this could be the number of frames,
* for audio data, this could be the number of audio samples,
@ -127,9 +133,11 @@ struct _GstBuffer {
guint64 offset;
guint64 offset_end;
/*< protected >*/
GstBufferFreeDataFunc free_data;
gpointer buffer_private;
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
@ -149,21 +157,21 @@ G_STMT_START { \
#define gst_buffer_ref_by_count(buf,c) GST_BUFFER (gst_data_ref_by_count (GST_DATA (buf), c))
#define gst_buffer_unref(buf) gst_data_unref (GST_DATA (buf))
/* copy buffer */
void gst_buffer_stamp (GstBuffer *dest, const GstBuffer *src);
#define gst_buffer_copy(buf) GST_BUFFER (gst_data_copy (GST_DATA (buf)))
#define gst_buffer_is_writable(buf) gst_data_is_writable (GST_DATA (buf))
#define gst_buffer_copy_on_write(buf) GST_BUFFER (gst_data_copy_on_write (GST_DATA (buf)))
GstCaps* gst_buffer_get_caps (GstBuffer *buffer);
void gst_buffer_set_caps (GstBuffer *buffer, GstCaps *caps);
/* creating a subbuffer */
GstBuffer* gst_buffer_create_sub (GstBuffer *parent, guint offset, guint size);
/* merge, span, or append two buffers, intelligently */
GstBuffer* gst_buffer_merge (GstBuffer *buf1, GstBuffer *buf2);
GstBuffer* gst_buffer_join (GstBuffer *buf1, GstBuffer *buf2);
/* span, two buffers, intelligently */
gboolean gst_buffer_is_span_fast (GstBuffer *buf1, GstBuffer *buf2);
GstBuffer* gst_buffer_span (GstBuffer *buf1, guint32 offset, GstBuffer *buf2, guint32 len);
/* --- private --- */
/* --- protected --- */
void _gst_buffer_initialize (void);
void gst_buffer_default_free (GstBuffer *buffer);

View file

@ -24,12 +24,15 @@
#include <signal.h>
#include "gst_private.h"
#include "gstatomic_impl.h"
#include <gst/gst.h>
//#define DEBUG_REFCOUNT
#define CAPS_POISON(caps) G_STMT_START{ \
if (caps) { \
GstCaps *_newcaps = gst_caps_copy (caps); \
gst_caps_free(caps); \
gst_caps_unref(caps); \
caps = _newcaps; \
} \
} G_STMT_END
@ -40,13 +43,15 @@
structure = _newstruct; \
} \
} G_STMT_END
#define IS_WRITABLE(caps) \
(gst_atomic_int_read(&(caps)->refcount) == 1)
static void gst_caps_transform_to_string (const GValue * src_value,
GValue * dest_value);
static gboolean gst_caps_from_string_inplace (GstCaps * caps,
const gchar * string);
static GstCaps *gst_caps_copy_conditional (const GstCaps * src);
static GstCaps *gst_caps_copy_conditional (GstCaps * src);
GType
gst_caps_get_type (void)
@ -56,7 +61,7 @@ gst_caps_get_type (void)
if (!gst_caps_type) {
gst_caps_type = g_boxed_type_register_static ("GstCaps",
(GBoxedCopyFunc) gst_caps_copy_conditional,
(GBoxedFreeFunc) gst_caps_free);
(GBoxedFreeFunc) gst_caps_unref);
g_value_register_transform_func (gst_caps_type,
G_TYPE_STRING, gst_caps_transform_to_string);
@ -80,9 +85,14 @@ gst_caps_new_empty (void)
{
GstCaps *caps = g_new0 (GstCaps, 1);
gst_atomic_int_init (&(caps)->refcount, 1);
caps->type = GST_TYPE_CAPS;
caps->structs = g_ptr_array_new ();
#ifdef DEBUG_REFCOUNT
GST_CAT_LOG (GST_CAT_CAPS, "created caps %p", caps);
#endif
return caps;
}
@ -188,8 +198,14 @@ gst_caps_new_full_valist (GstStructure * structure, va_list var_args)
* gst_caps_copy:
* @caps: the #GstCaps to copy
*
* Deeply copies a #GstCaps, including all structures and all the
* structures' values.
* Creates a new #GstCaps as a copy of the old @caps. The new caps will have a
* refcount of 1, owned by the caller. The structures are copied as well.
*
* Note that this function is the semantic equivalent of a gst_caps_ref()
* followed by a gst_caps_make_writable(). If you only want to hold on to a
* reference to the data, you should use gst_caps_ref().
*
* When you are finished with the caps, call gst_caps_unref() on it.
*
* Returns: the new #GstCaps
*/
@ -213,32 +229,118 @@ gst_caps_copy (const GstCaps * caps)
return newcaps;
}
/**
* gst_caps_free:
* @caps: the #GstCaps to free
*
* Frees a #GstCaps and all its structures and the structures'
* values.
*/
void
gst_caps_free (GstCaps * caps)
static void
_gst_caps_free (GstCaps * caps)
{
GstStructure *structure;
int i;
g_return_if_fail (GST_IS_CAPS (caps));
/* The refcount must be 0, but since we're only called by gst_caps_unref,
* don't bother testing. */
for (i = 0; i < caps->structs->len; i++) {
structure = gst_caps_get_structure (caps, i);
structure = (GstStructure *) gst_caps_get_structure (caps, i);
gst_structure_set_parent_refcount (structure, NULL);
gst_structure_free (structure);
}
g_ptr_array_free (caps->structs, TRUE);
#ifdef USE_POISONING
memset (caps, 0xff, sizeof (GstCaps));
#endif
gst_atomic_int_destroy (&(caps)->refcount);
g_free (caps);
}
/**
* gst_caps_make_writable:
* @caps: the #GstCaps to make writable
*
* Returns a writable copy of @caps.
*
* If there is only one reference count on @caps, the caller must be the owner,
* and so this function will return the caps object unchanged. If on the other
* hand there is more than one reference on the object, a new caps object will
* be returned. The caller's reference on @caps will be removed, and instead the
* caller will own a reference to the returned object.
*
* In short, this function unrefs the caps in the argument and refs the caps
* that it returns. Don't access the argument after calling this function. See
* also: gst_caps_ref().
*
* Returns: the same #GstCaps object.
*/
GstCaps *
gst_caps_make_writable (GstCaps * caps)
{
GstCaps *copy;
g_return_val_if_fail (caps != NULL, NULL);
/* we are the only instance reffing this caps */
if (gst_atomic_int_read (&caps->refcount) == 1)
return caps;
/* else copy */
copy = gst_caps_copy (caps);
gst_caps_unref (caps);
return copy;
}
/**
* gst_caps_ref:
* @caps: the #GstCaps to reference
*
* Add a reference to a #GstCaps object.
*
* From this point on, until the caller calls gst_caps_unref() or
* gst_caps_make_writable(), it is guaranteed that the caps object will not
* change. This means its structures won't change, etc. To use a #GstCaps
* object, you must always have a refcount on it -- either the one made
* implicitly by gst_caps_new(), or via taking one explicitly with this
* function.
*
* Returns: the same #GstCaps object.
*/
GstCaps *
gst_caps_ref (GstCaps * caps)
{
g_return_val_if_fail (caps != NULL, NULL);
#ifdef DEBUG_REFCOUNT
GST_CAT_LOG (GST_CAT_CAPS, "%p %d->%d", caps,
GST_CAPS_REFCOUNT_VALUE (caps), GST_CAPS_REFCOUNT_VALUE (caps) + 1);
#endif
gst_atomic_int_inc (&caps->refcount);
return caps;
}
/**
* gst_caps_unref:
* @caps: the #GstCaps to unref
*
* Unref a #GstCaps and and free all its structures and the
* structures' values when the refcount reaches 0.
*/
void
gst_caps_unref (GstCaps * caps)
{
g_return_if_fail (caps != NULL);
g_return_if_fail (GST_CAPS_REFCOUNT_VALUE (caps) > 0);
#ifdef DEBUG_REFCOUNT
GST_CAT_LOG (GST_CAT_CAPS, "%p %d->%d", caps,
GST_CAPS_REFCOUNT_VALUE (caps), GST_CAPS_REFCOUNT_VALUE (caps) - 1);
#endif
/* if we ended up with the refcount at zero, free the caps */
if (gst_atomic_int_dec_and_test (&caps->refcount)) {
_gst_caps_free (caps);
}
}
/**
* gst_static_caps_get:
* @static_caps: the #GstStaticCaps to convert
@ -255,12 +357,18 @@ gst_static_caps_get (GstStaticCaps * static_caps)
if (caps->type == 0) {
caps->type = GST_TYPE_CAPS;
/* initialize the caps to a refcount of 1 so the caps can be writable... */
gst_atomic_int_init (&(caps)->refcount, 1);
caps->structs = g_ptr_array_new ();
ret = gst_caps_from_string_inplace (caps, static_caps->string);
if (!ret) {
g_critical ("Could not convert static caps \"%s\"", static_caps->string);
}
/* and now that we return it to the user, keep a ref for ourselves. This
* makes the caps immutable... AND INVINCIBLE! WOULD YOU LIKE TO TRY MY
* IMMUTABLE CAPS STYLE? I AM A CAPS WARRIOR!!! */
gst_caps_ref (caps);
}
return caps;
@ -268,14 +376,24 @@ gst_static_caps_get (GstStaticCaps * static_caps)
/* manipulation */
static GstStructure *
gst_caps_remove_and_get_structure (GstCaps * caps, guint idx)
{
/* don't use index_fast, gst_caps_simplify relies on the order */
GstStructure *s = g_ptr_array_remove_index (caps->structs, idx);
gst_structure_set_parent_refcount (s, NULL);
return s;
}
/**
* gst_caps_append:
* @caps1: the #GstCaps that will be appended to
* @caps2: the #GstCaps to append
*
* Appends the structures contained in @caps2 to @caps1. The structures
* in @caps2 are not copied -- they are transferred to @caps1, and then
* @caps2 is freed.
* Appends the structures contained in @caps2 to @caps1. The structures in
* @caps2 are not copied -- they are transferred to @caps1, and then @caps2 is
* freed. If either caps is ANY, the resulting caps will be ANY.
*/
void
gst_caps_append (GstCaps * caps1, GstCaps * caps2)
@ -285,6 +403,8 @@ gst_caps_append (GstCaps * caps1, GstCaps * caps2)
g_return_if_fail (GST_IS_CAPS (caps1));
g_return_if_fail (GST_IS_CAPS (caps2));
g_return_if_fail (IS_WRITABLE (caps1));
g_return_if_fail (IS_WRITABLE (caps2));
#ifdef USE_POISONING
CAPS_POISON (caps2);
@ -292,21 +412,19 @@ gst_caps_append (GstCaps * caps1, GstCaps * caps2)
if (gst_caps_is_any (caps1) || gst_caps_is_any (caps2)) {
/* FIXME: this leaks */
caps1->flags |= GST_CAPS_FLAGS_ANY;
for (i = 0; i < caps2->structs->len; i++) {
structure = gst_caps_get_structure (caps2, i);
gst_structure_remove_all_fields (structure);
for (i = caps2->structs->len - 1; i >= 0; i--) {
structure = gst_caps_remove_and_get_structure (caps2, i);
gst_structure_free (structure);
}
} else {
for (i = 0; i < caps2->structs->len; i++) {
structure = gst_caps_get_structure (caps2, i);
int len = caps2->structs->len;
for (i = 0; i < len; i++) {
structure = gst_caps_remove_and_get_structure (caps2, 0);
gst_caps_append_structure (caps1, structure);
}
}
g_ptr_array_free (caps2->structs, TRUE);
#ifdef USE_POISONING
memset (caps2, 0xff, sizeof (GstCaps));
#endif
g_free (caps2);
gst_caps_unref (caps2); /* guaranteed to free it */
}
/**
@ -321,24 +439,20 @@ void
gst_caps_append_structure (GstCaps * caps, GstStructure * structure)
{
g_return_if_fail (GST_IS_CAPS (caps));
g_return_if_fail (IS_WRITABLE (caps));
if (structure) {
g_return_if_fail (structure->parent_refcount == NULL);
#if 0
#ifdef USE_POISONING
STRUCTURE_POISON (structure);
#endif
#endif
gst_structure_set_parent_refcount (structure, &caps->refcount);
g_ptr_array_add (caps->structs, structure);
}
}
static GstStructure *
gst_caps_remove_and_get_structure (GstCaps * caps, guint idx)
{
/* don't use index_fast, gst_caps_simplify relies on the order */
return g_ptr_array_remove_index (caps->structs, idx);
}
/*
* gst_caps_remove_structure:
* @caps: the #GstCaps to remove from
@ -354,6 +468,7 @@ gst_caps_remove_structure (GstCaps * caps, guint idx)
g_return_if_fail (caps != NULL);
g_return_if_fail (idx <= gst_caps_get_size (caps));
g_return_if_fail (IS_WRITABLE (caps));
structure = gst_caps_remove_and_get_structure (caps, idx);
gst_structure_free (structure);
@ -417,17 +532,18 @@ gst_caps_get_structure (const GstCaps * caps, int index)
return g_ptr_array_index (caps->structs, index);
}
/**
* gst_caps_copy_1:
* @caps: the @GstCaps to copy
*
* Creates a new @GstCaps and appends a copy of the first structure
* contained in @caps.
*
* Returns: the new @GstCaps
/**
* gst_caps_copy_nth:
* @caps: the @GstCaps to copy
* @nth: the nth structure to copy
*
* Creates a new @GstCaps and appends a copy of the nth structure
* contained in @caps.
*
* Returns: the new @GstCaps
*/
GstCaps *
gst_caps_copy_1 (const GstCaps * caps)
gst_caps_copy_nth (const GstCaps * caps, gint nth)
{
GstCaps *newcaps;
GstStructure *structure;
@ -437,8 +553,8 @@ gst_caps_copy_1 (const GstCaps * caps)
newcaps = gst_caps_new_empty ();
newcaps->flags = caps->flags;
if (caps->structs->len > 0) {
structure = gst_caps_get_structure (caps, 0);
if (caps->structs->len > nth) {
structure = gst_caps_get_structure (caps, nth);
gst_caps_append_structure (newcaps, gst_structure_copy (structure));
}
@ -463,6 +579,7 @@ gst_caps_set_simple (GstCaps * caps, char *field, ...)
g_return_if_fail (GST_IS_CAPS (caps));
g_return_if_fail (caps->structs->len == 1);
g_return_if_fail (IS_WRITABLE (caps));
structure = gst_caps_get_structure (caps, 0);
@ -488,6 +605,7 @@ gst_caps_set_simple_valist (GstCaps * caps, char *field, va_list varargs)
g_return_if_fail (GST_IS_CAPS (caps));
g_return_if_fail (caps->structs->len != 1);
g_return_if_fail (IS_WRITABLE (caps));
structure = gst_caps_get_structure (caps, 0);
@ -531,27 +649,9 @@ gst_caps_is_empty (const GstCaps * caps)
return (caps->structs == NULL) || (caps->structs->len == 0);
}
/**
* gst_caps_is_chained:
* @caps: the @GstCaps to test
*
* Determines if @caps contains multiple #GstStructures.
*
* This function is deprecated, and should not be used in new code.
* Use #gst_caps_is_simple() instead.
*
* Returns: TRUE if @caps contains more than one structure
*/
gboolean
gst_caps_is_chained (const GstCaps * caps)
{
g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
return (caps->structs->len > 1);
}
static gboolean
gst_caps_is_fixed_foreach (GQuark field_id, GValue * value, gpointer unused)
gst_caps_is_fixed_foreach (GQuark field_id, const GValue * value,
gpointer unused)
{
return gst_value_is_fixed (value);
}
@ -582,7 +682,8 @@ gst_caps_is_fixed (const GstCaps * caps)
}
static gboolean
gst_structure_is_equal_foreach (GQuark field_id, GValue * val2, gpointer data)
gst_structure_is_equal_foreach (GQuark field_id, const GValue * val2,
gpointer data)
{
GstStructure *struct1 = (GstStructure *) data;
const GValue *val1 = gst_structure_id_get_value (struct1, field_id);
@ -675,7 +776,7 @@ gst_caps_is_subset (const GstCaps * subset, const GstCaps * superset)
caps = gst_caps_subtract (subset, superset);
ret = gst_caps_is_empty (caps);
gst_caps_free (caps);
gst_caps_unref (caps);
return ret;
}
@ -711,7 +812,8 @@ typedef struct
IntersectData;
static gboolean
gst_caps_structure_intersect_field (GQuark id, GValue * val1, gpointer data)
gst_caps_structure_intersect_field (GQuark id, const GValue * val1,
gpointer data)
{
IntersectData *idata = (IntersectData *) data;
GValue dest_value = { 0 };
@ -818,10 +920,11 @@ gst_caps_structure_union (const GstStructure * struct1,
GstCaps *
gst_caps_intersect (const GstCaps * caps1, const GstCaps * caps2)
{
int i, j;
int i, j, k;
GstStructure *struct1;
GstStructure *struct2;
GstCaps *dest;
GstStructure *istruct;
g_return_val_if_fail (GST_IS_CAPS (caps1), NULL);
g_return_val_if_fail (GST_IS_CAPS (caps2), NULL);
@ -835,18 +938,44 @@ gst_caps_intersect (const GstCaps * caps1, const GstCaps * caps2)
return gst_caps_copy (caps1);
dest = gst_caps_new_empty ();
for (i = 0; i < caps1->structs->len; i++) {
struct1 = gst_caps_get_structure (caps1, i);
for (j = 0; j < caps2->structs->len; j++) {
GstStructure *istruct;
struct2 = gst_caps_get_structure (caps2, j);
/* run zigzag on top line then right line, this preserves the caps order
* much better than a simple loop.
*
* This algorithm zigzags over the caps structures as demonstrated in
* the folowing matrix:
*
* caps1
* +-------------
* | 1 2 4 7
* caps2 | 3 5 8 10
* | 6 9 11 12
*
* First we iterate over the caps1 structures (top line) intersecting
* the structures diagonally down, then we iterate over the caps2
* structures.
*/
for (i = 0; i < caps1->structs->len + caps2->structs->len - 1; i++) {
/* caps1 index goes from 0 to caps1->structs->len-1 */
j = MIN (i, caps1->structs->len - 1);
/* caps2 index stays 0 until i reaches caps1->structs->len, then it counts
* up from 1 to caps2->structs->len - 1 */
k = MAX (0, i - j);
/* now run the diagonal line, end condition is the left or bottom
* border */
while (k < caps2->structs->len && j >= 0) {
struct1 = gst_caps_get_structure (caps1, j);
struct2 = gst_caps_get_structure (caps2, k);
istruct = gst_caps_structure_intersect (struct1, struct2);
gst_caps_append_structure (dest, istruct);
/* move down left */
k++;
j--;
}
}
gst_caps_do_simplify (dest);
return dest;
}
@ -859,8 +988,8 @@ typedef struct
SubtractionEntry;
gboolean
gst_caps_structure_subtract_field (GQuark field_id, GValue * value,
static gboolean
gst_caps_structure_subtract_field (GQuark field_id, const GValue * value,
gpointer user_data)
{
SubtractionEntry *e = user_data;
@ -951,7 +1080,7 @@ gst_caps_subtract (const GstCaps * minuend, const GstCaps * subtrahend)
for (i = 0; i < subtrahend->structs->len; i++) {
sub = gst_caps_get_structure (subtrahend, i);
if (dest) {
gst_caps_free (src);
gst_caps_unref (src);
src = dest;
}
dest = gst_caps_new_empty ();
@ -975,12 +1104,12 @@ gst_caps_subtract (const GstCaps * minuend, const GstCaps * subtrahend)
}
}
if (gst_caps_is_empty (dest)) {
gst_caps_free (src);
gst_caps_unref (src);
return dest;
}
}
gst_caps_free (src);
gst_caps_unref (src);
gst_caps_do_simplify (dest);
return dest;
}
@ -1020,7 +1149,7 @@ typedef struct _NormalizeForeach
NormalizeForeach;
static gboolean
gst_caps_normalize_foreach (GQuark field_id, GValue * value, gpointer ptr)
gst_caps_normalize_foreach (GQuark field_id, const GValue * value, gpointer ptr)
{
NormalizeForeach *nf = (NormalizeForeach *) ptr;
GValue val = { 0 };
@ -1090,7 +1219,7 @@ gst_caps_compare_structures (gconstpointer one, gconstpointer two)
if (ret)
return ret;
return gst_structure_n_fields (struct1) - gst_structure_n_fields (struct2);
return gst_structure_n_fields (struct2) - gst_structure_n_fields (struct1);
}
/**
@ -1126,7 +1255,7 @@ typedef struct
UnionField;
static gboolean
gst_caps_structure_figure_out_union (GQuark field_id, GValue * value,
gst_caps_structure_figure_out_union (GQuark field_id, const GValue * value,
gpointer user_data)
{
UnionField *u = user_data;
@ -1214,6 +1343,16 @@ gst_caps_structure_simplify (GstStructure ** result,
return FALSE;
}
static void
gst_caps_switch_structures (GstCaps * caps, GstStructure * old,
GstStructure * new, gint i)
{
gst_structure_set_parent_refcount (old, NULL);
gst_structure_free (old);
gst_structure_set_parent_refcount (new, &caps->refcount);
g_ptr_array_index (caps->structs, i) = new;
}
/**
* gst_caps_do_simplify:
* @caps: a #GstCaps to simplify
@ -1233,6 +1372,7 @@ gst_caps_do_simplify (GstCaps * caps)
gboolean changed = FALSE;
g_return_val_if_fail (caps != NULL, FALSE);
g_return_val_if_fail (IS_WRITABLE (caps), FALSE);
if (gst_caps_get_size (caps) < 2)
return FALSE;
@ -1261,9 +1401,7 @@ gst_caps_do_simplify (GstCaps * caps)
result ? gst_structure_to_string (result) : "---");
#endif
if (result) {
gst_structure_free (simplify);
g_ptr_array_index (caps->structs, i) = result;
simplify = result;
gst_caps_switch_structures (caps, simplify, result, i);
} else {
gst_caps_remove_structure (caps, i);
start--;
@ -1340,7 +1478,7 @@ gst_caps_replace (GstCaps ** caps, GstCaps * newcaps)
#endif
#endif
if (*caps)
gst_caps_free (*caps);
gst_caps_unref (*caps);
*caps = newcaps;
}
@ -1454,7 +1592,7 @@ gst_caps_from_string (const gchar * string)
if (gst_caps_from_string_inplace (caps, string)) {
return caps;
} else {
gst_caps_free (caps);
gst_caps_unref (caps);
return NULL;
}
}
@ -1473,140 +1611,11 @@ gst_caps_transform_to_string (const GValue * src_value, GValue * dest_value)
}
static GstCaps *
gst_caps_copy_conditional (const GstCaps * src)
gst_caps_copy_conditional (GstCaps * src)
{
if (src) {
return gst_caps_copy (src);
return gst_caps_ref (src);
} else {
return NULL;
}
}
/* fixate utility functions */
/**
* gst_caps_structure_fixate_field_nearest_int:
* @structure: a #GstStructure
* @field_name: a field in @structure
* @target: the target value of the fixation
*
* Fixates a #GstStructure by changing the given field to the nearest
* integer to @target that is a subset of the existing field.
*
* Returns: TRUE if the structure could be fixated
*/
gboolean
gst_caps_structure_fixate_field_nearest_int (GstStructure * structure,
const char *field_name, int target)
{
const GValue *value;
g_return_val_if_fail (gst_structure_has_field (structure, field_name), FALSE);
value = gst_structure_get_value (structure, field_name);
if (G_VALUE_TYPE (value) == G_TYPE_INT) {
/* already fixed */
return FALSE;
} else if (G_VALUE_TYPE (value) == GST_TYPE_INT_RANGE) {
int x;
x = gst_value_get_int_range_min (value);
if (target < x)
target = x;
x = gst_value_get_int_range_max (value);
if (target > x)
target = x;
gst_structure_set (structure, field_name, G_TYPE_INT, target, NULL);
return TRUE;
} else if (G_VALUE_TYPE (value) == GST_TYPE_LIST) {
const GValue *list_value;
int i, n;
int best = 0;
int best_index = -1;
n = gst_value_list_get_size (value);
for (i = 0; i < n; i++) {
list_value = gst_value_list_get_value (value, i);
if (G_VALUE_TYPE (list_value) == G_TYPE_INT) {
int x = g_value_get_int (list_value);
if (best_index == -1 || (ABS (target - x) < ABS (target - best))) {
best_index = i;
best = x;
}
}
}
if (best_index != -1) {
gst_structure_set (structure, field_name, G_TYPE_INT, best, NULL);
return TRUE;
}
return FALSE;
}
return FALSE;
}
/**
* gst_caps_structure_fixate_field_nearest_double:
* @structure: a #GstStructure
* @field_name: a field in @structure
* @target: the target value of the fixation
*
* Fixates a #GstStructure by changing the given field to the nearest
* double to @target that is a subset of the existing field.
*
* Returns: TRUE if the structure could be fixated
*/
gboolean
gst_caps_structure_fixate_field_nearest_double (GstStructure * structure,
const char *field_name, double target)
{
const GValue *value;
g_return_val_if_fail (gst_structure_has_field (structure, field_name), FALSE);
value = gst_structure_get_value (structure, field_name);
if (G_VALUE_TYPE (value) == G_TYPE_DOUBLE) {
/* already fixed */
return FALSE;
} else if (G_VALUE_TYPE (value) == GST_TYPE_DOUBLE_RANGE) {
double x;
x = gst_value_get_double_range_min (value);
if (target < x)
target = x;
x = gst_value_get_double_range_max (value);
if (target > x)
target = x;
gst_structure_set (structure, field_name, G_TYPE_DOUBLE, target, NULL);
return TRUE;
} else if (G_VALUE_TYPE (value) == GST_TYPE_LIST) {
const GValue *list_value;
int i, n;
double best = 0;
int best_index = -1;
n = gst_value_list_get_size (value);
for (i = 0; i < n; i++) {
list_value = gst_value_list_get_value (value, i);
if (G_VALUE_TYPE (list_value) == G_TYPE_DOUBLE) {
double x = g_value_get_double (list_value);
if (best_index == -1 || (ABS (target - x) < ABS (target - best))) {
best_index = i;
best = x;
}
}
}
if (best_index != -1) {
gst_structure_set (structure, field_name, G_TYPE_DOUBLE, best, NULL);
return TRUE;
}
return FALSE;
}
return FALSE;
}

View file

@ -54,18 +54,30 @@ G_BEGIN_DECLS
typedef struct _GstCaps GstCaps;
typedef struct _GstStaticCaps GstStaticCaps;
/* refcount */
#define GST_CAPS_REFCOUNT(caps) ((GST_CAPS(caps))->refcount)
#define GST_CAPS_REFCOUNT_VALUE(caps) (gst_atomic_int_read (&(GST_CAPS(caps))->refcount))
struct _GstCaps {
GType type;
/*< public >*/ /* with COW */
/* refcounting */
GstAtomicInt refcount;
guint16 flags;
GPtrArray *structs;
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
struct _GstStaticCaps {
/*< public >*/
GstCaps caps;
const char *string;
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
@ -79,8 +91,13 @@ GstCaps * gst_caps_new_full (GstStru
...);
GstCaps * gst_caps_new_full_valist (GstStructure *structure,
va_list var_args);
GstCaps * gst_caps_copy (const GstCaps *caps);
void gst_caps_free (GstCaps *caps);
/* reference counting */
GstCaps * gst_caps_ref (GstCaps* caps);
GstCaps * gst_caps_copy (const GstCaps * caps);
GstCaps * gst_caps_make_writable (GstCaps *caps);
void gst_caps_unref (GstCaps* caps);
G_CONST_RETURN GstCaps * gst_static_caps_get (GstStaticCaps *static_caps);
/* manipulation */
@ -91,10 +108,7 @@ void gst_caps_append_structure (GstCaps
int gst_caps_get_size (const GstCaps *caps);
GstStructure * gst_caps_get_structure (const GstCaps *caps,
int index);
#ifndef GST_DISABLE_DEPRECATED
GstCaps * gst_caps_split_one (GstCaps *caps);
GstCaps * gst_caps_copy_1 (const GstCaps *caps);
#endif
GstCaps * gst_caps_copy_nth (const GstCaps * caps, gint nth);
void gst_caps_set_simple (GstCaps *caps,
char *field, ...);
void gst_caps_set_simple_valist (GstCaps *caps,
@ -104,11 +118,6 @@ void gst_caps_set_simple_valist (GstCaps
/* tests */
gboolean gst_caps_is_any (const GstCaps *caps);
gboolean gst_caps_is_empty (const GstCaps *caps);
#ifndef GST_DISABLE_DEPRECATED
gboolean gst_caps_is_chained (const GstCaps *caps);
gboolean gst_caps_is_equal_fixed (const GstCaps *caps1,
const GstCaps *caps2);
#endif
gboolean gst_caps_is_fixed (const GstCaps *caps);
gboolean gst_caps_is_always_compatible (const GstCaps *caps1,
const GstCaps *caps2);
@ -125,9 +134,6 @@ GstCaps * gst_caps_subtract (const GstCaps *minuend,
GstCaps * gst_caps_union (const GstCaps *caps1,
const GstCaps *caps2);
GstCaps * gst_caps_normalize (const GstCaps *caps);
#ifndef GST_DISABLE_DEPRECATED
GstCaps * gst_caps_simplify (const GstCaps *caps);
#endif
gboolean gst_caps_do_simplify (GstCaps *caps);
#ifndef GST_DISABLE_LOADSAVE

View file

@ -1,6 +1,7 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* 2004 Wim Taymans <wim@fluendo.com>
*
* gstclock.c: Clock subsystem for maintaining time sync
*
@ -27,6 +28,7 @@
#include "gstclock.h"
#include "gstinfo.h"
#include "gstmemchunk.h"
#include "gstatomic_impl.h"
#ifndef GST_DISABLE_TRACE
/* #define GST_WITH_ALLOC_TRACE */
@ -47,9 +49,6 @@ enum
static GstMemChunk *_gst_clock_entries_chunk;
void gst_clock_id_unlock (GstClockID id);
static void gst_clock_class_init (GstClockClass * klass);
static void gst_clock_init (GstClock * clock);
static void gst_clock_dispose (GObject * object);
@ -75,25 +74,86 @@ gst_clock_entry_new (GstClock * clock, GstClockTime time,
#ifndef GST_DISABLE_TRACE
gst_alloc_trace_new (_gst_clock_entry_trace, entry);
#endif
GST_CAT_DEBUG (GST_CAT_CLOCK, "created entry %p", entry);
gst_atomic_int_init (&entry->refcount, 1);
entry->clock = clock;
entry->time = time;
entry->interval = interval;
entry->type = type;
entry->status = GST_CLOCK_ENTRY_OK;
entry->status = GST_CLOCK_BUSY;
return (GstClockID) entry;
}
/**
* gst_clock_id_ref:
* @id: The clockid to ref
*
* Increase the refcount of the given clockid.
*
* Returns: The same #GstClockID with increased refcount.
*
* MT safe.
*/
GstClockID
gst_clock_id_ref (GstClockID id)
{
g_return_val_if_fail (id != NULL, NULL);
gst_atomic_int_inc (&((GstClockEntry *) id)->refcount);
return id;
}
static void
_gst_clock_id_free (GstClockID id)
{
g_return_if_fail (id != NULL);
GST_CAT_DEBUG (GST_CAT_CLOCK, "freed entry %p", id);
#ifndef GST_DISABLE_TRACE
gst_alloc_trace_free (_gst_clock_entry_trace, id);
#endif
gst_mem_chunk_free (_gst_clock_entries_chunk, id);
}
/**
* gst_clock_id_unref:
* @id: The clockid to unref
*
* Unref the given clockid. When the refcount reaches 0 the
* #GstClockID will be freed.
*
* MT safe.
*/
void
gst_clock_id_unref (GstClockID id)
{
gint zero;
g_return_if_fail (id != NULL);
zero = gst_atomic_int_dec_and_test (&((GstClockEntry *) id)->refcount);
/* if we ended up with the refcount at zero, free the id */
if (zero) {
_gst_clock_id_free (id);
}
}
/**
* gst_clock_new_single_shot_id
* @clock: The clockid to get a single shot notification from
* @time: the requested time
*
* Get an ID from the given clock to trigger a single shot
* notification at the requested time.
* notification at the requested time. The single shot id should be
* unreffed after usage.
*
* Returns: An id that can be used to request the time notification.
*
* MT safe.
*/
GstClockID
gst_clock_new_single_shot_id (GstClock * clock, GstClockTime time)
@ -112,9 +172,12 @@ gst_clock_new_single_shot_id (GstClock * clock, GstClockTime time)
*
* Get an ID from the given clock to trigger a periodic notification.
* The periodeic notifications will be start at time start_time and
* will then be fired with the given interval.
* will then be fired with the given interval. The id should be unreffed
* after usage.
*
* Returns: An id that can be used to request the time notification.
*
* MT safe.
*/
GstClockID
gst_clock_new_periodic_id (GstClock * clock, GstClockTime start_time,
@ -128,13 +191,45 @@ gst_clock_new_periodic_id (GstClock * clock, GstClockTime start_time,
start_time, interval, GST_CLOCK_ENTRY_PERIODIC);
}
/**
* gst_clock_id_compare_func
* @id1: A clockid
* @id2: A clockid to compare with
*
* Compares the two GstClockID instances. This function can be used
* as a GCompareFunc when sorting ids.
*
* Returns: negative value if a < b; zero if a = b; positive value if a > b
*
* MT safe.
*/
gint
gst_clock_id_compare_func (gconstpointer id1, gconstpointer id2)
{
GstClockEntry *entry1, *entry2;
entry1 = (GstClockEntry *) id1;
entry2 = (GstClockEntry *) id2;
if (GST_CLOCK_ENTRY_TIME (entry1) > GST_CLOCK_ENTRY_TIME (entry2)) {
return 1;
}
if (GST_CLOCK_ENTRY_TIME (entry1) < GST_CLOCK_ENTRY_TIME (entry2)) {
return -1;
}
return entry1 - entry2;
}
/**
* gst_clock_id_get_time
* @id: The clockid to query
*
* Get the time of the clock ID
*
* Returns: the time of the given clock id
* Returns: the time of the given clock id.
*
* MT safe.
*/
GstClockTime
gst_clock_id_get_time (GstClockID id)
@ -151,16 +246,18 @@ gst_clock_id_get_time (GstClockID id)
* @jitter: A pointer that will contain the jitter
*
* Perform a blocking wait on the given ID. The jitter arg can be
* NULL
* NULL.
*
* Returns: the result of the blocking wait.
*
* MT safe.
*/
GstClockReturn
gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter)
{
GstClockEntry *entry;
GstClock *clock;
GstClockReturn res = GST_CLOCK_UNSUPPORTED;
GstClockReturn res;
GstClockTime requested;
GstClockClass *cclass;
@ -169,43 +266,49 @@ gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter)
entry = (GstClockEntry *) id;
requested = GST_CLOCK_ENTRY_TIME (entry);
if (!GST_CLOCK_TIME_IS_VALID (requested)) {
GST_CAT_DEBUG (GST_CAT_CLOCK, "invalid time requested, returning _TIMEOUT");
return GST_CLOCK_TIMEOUT;
}
if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested)))
goto invalid_time;
if (G_UNLIKELY (entry->status == GST_CLOCK_UNSCHEDULED))
goto unscheduled;
clock = GST_CLOCK_ENTRY_CLOCK (entry);
cclass = GST_CLOCK_GET_CLASS (clock);
if (cclass->wait) {
GstClockTime now;
if (G_LIKELY (cclass->wait)) {
GST_LOCK (clock);
clock->entries = g_list_prepend (clock->entries, entry);
GST_UNLOCK (clock);
GST_CAT_DEBUG (GST_CAT_CLOCK, "waiting on clock");
do {
res = cclass->wait (clock, entry);
}
while (res == GST_CLOCK_ENTRY_RESTART);
GST_CAT_DEBUG (GST_CAT_CLOCK, "done waiting");
GST_LOCK (clock);
clock->entries = g_list_remove (clock->entries, entry);
GST_UNLOCK (clock);
GST_CAT_DEBUG (GST_CAT_CLOCK, "waiting on clock entry %p", id);
res = cclass->wait (clock, entry);
GST_CAT_DEBUG (GST_CAT_CLOCK, "done waiting entry %p", id);
if (jitter) {
now = gst_clock_get_time (clock);
GstClockTime now = gst_clock_get_time (clock);
*jitter = now - requested;
}
if (entry->type == GST_CLOCK_ENTRY_PERIODIC) {
entry->time += entry->interval;
}
if (clock->stats) {
gst_clock_update_stats (clock);
}
} else {
res = GST_CLOCK_UNSUPPORTED;
}
return res;
/* ERRORS */
invalid_time:
{
GST_CAT_DEBUG (GST_CAT_CLOCK, "invalid time requested, returning _BADTIME");
return GST_CLOCK_BADTIME;
}
unscheduled:
{
GST_CAT_DEBUG (GST_CAT_CLOCK, "entry was unscheduled return _UNSCHEDULED");
return GST_CLOCK_UNSCHEDULED;
}
}
/**
@ -215,9 +318,14 @@ gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter)
* @user_data: User data passed in the calback
*
* Register a callback on the given clockid with the given
* function and user_data.
* function and user_data. When passing an id with an invalid
* time to this function, the callback will be called immediatly
* with a time set to GST_CLOCK_TIME_NONE. The callback will
* be called when the time of the id has been reached.
*
* Returns: the result of the non blocking wait.
*
* MT safe.
*/
GstClockReturn
gst_clock_id_wait_async (GstClockID id,
@ -225,19 +333,22 @@ gst_clock_id_wait_async (GstClockID id,
{
GstClockEntry *entry;
GstClock *clock;
GstClockReturn res = GST_CLOCK_UNSUPPORTED;
GstClockReturn res;
GstClockClass *cclass;
GstClockTime requested;
g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR);
g_return_val_if_fail (func != NULL, GST_CLOCK_ERROR);
entry = (GstClockEntry *) id;
clock = entry->clock;
requested = GST_CLOCK_ENTRY_TIME (entry);
clock = GST_CLOCK_ENTRY_CLOCK (entry);
if (!GST_CLOCK_TIME_IS_VALID (GST_CLOCK_ENTRY_TIME (entry))) {
(func) (clock, GST_CLOCK_TIME_NONE, id, user_data);
return GST_CLOCK_TIMEOUT;
}
if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested)))
goto invalid_time;
if (G_UNLIKELY (entry->status == GST_CLOCK_UNSCHEDULED))
goto unscheduled;
cclass = GST_CLOCK_GET_CLASS (clock);
@ -246,24 +357,35 @@ gst_clock_id_wait_async (GstClockID id,
entry->user_data = user_data;
res = cclass->wait_async (clock, entry);
} else {
res = GST_CLOCK_UNSUPPORTED;
}
return res;
}
static void
gst_clock_reschedule_func (GstClockEntry * entry)
{
entry->status = GST_CLOCK_ENTRY_OK;
gst_clock_id_unlock ((GstClockID) entry);
/* ERRORS */
invalid_time:
{
(func) (clock, GST_CLOCK_TIME_NONE, id, user_data);
GST_CAT_DEBUG (GST_CAT_CLOCK, "invalid time requested, returning _BADTIME");
return GST_CLOCK_BADTIME;
}
unscheduled:
{
GST_CAT_DEBUG (GST_CAT_CLOCK, "entry was unscheduled return _UNSCHEDULED");
return GST_CLOCK_UNSCHEDULED;
}
}
/**
* gst_clock_id_unschedule:
* @id: The id to unschedule
*
* Cancel an outstanding async notification request with the given ID.
* Cancel an outstanding request with the given ID. This can either
* be an outstanding async notification or a pending sync notification.
* After this call, the @id cannot be used anymore to receive sync or
* async notifications, you need to create a new GstClockID.
*
* MT safe.
*/
void
gst_clock_id_unschedule (GstClockID id)
@ -283,47 +405,6 @@ gst_clock_id_unschedule (GstClockID id)
cclass->unschedule (clock, entry);
}
/**
* gst_clock_id_free:
* @id: The clockid to free
*
* Free the resources held by the given id
*/
void
gst_clock_id_free (GstClockID id)
{
g_return_if_fail (id != NULL);
#ifndef GST_DISABLE_TRACE
gst_alloc_trace_free (_gst_clock_entry_trace, id);
#endif
gst_mem_chunk_free (_gst_clock_entries_chunk, id);
}
/**
* gst_clock_id_unlock:
* @id: The clockid to unlock
*
* Unlock the givan ClockID.
*/
void
gst_clock_id_unlock (GstClockID id)
{
GstClockEntry *entry;
GstClock *clock;
GstClockClass *cclass;
g_return_if_fail (id != NULL);
entry = (GstClockEntry *) id;
clock = entry->clock;
cclass = GST_CLOCK_GET_CLASS (clock);
if (cclass->unlock)
cclass->unlock (clock, entry);
}
/**
* GstClock abstract base class implementation
@ -382,30 +463,17 @@ gst_clock_class_init (GstClockClass * klass)
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_STATS,
g_param_spec_boolean ("stats", "Stats", "Enable clock stats",
FALSE, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAX_DIFF,
g_param_spec_int64 ("max-diff", "Max diff",
"The maximum amount of time to wait in nanoseconds", 0, G_MAXINT64,
DEFAULT_MAX_DIFF, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_EVENT_DIFF,
g_param_spec_uint64 ("event-diff", "event diff",
"The amount of time that may elapse until 2 events are treated as happening at different times",
0, G_MAXUINT64, DEFAULT_EVENT_DIFF,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
}
static void
gst_clock_init (GstClock * clock)
{
clock->max_diff = DEFAULT_MAX_DIFF;
clock->start_time = 0;
clock->adjust = 0;
clock->last_time = 0;
clock->entries = NULL;
clock->entries_changed = g_cond_new ();
clock->flags = 0;
clock->stats = FALSE;
clock->active_mutex = g_mutex_new ();
clock->active_cond = g_cond_new ();
}
static void
@ -413,48 +481,11 @@ gst_clock_dispose (GObject * object)
{
GstClock *clock = GST_CLOCK (object);
g_mutex_free (clock->active_mutex);
g_cond_free (clock->active_cond);
g_cond_free (clock->entries_changed);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
/**
* gst_clock_set_speed
* @clock: a #GstClock to modify
* @speed: the speed to set on the clock
*
* Sets the speed on the given clock. 1.0 is the default
* speed.
*
* Returns: the new speed of the clock.
*/
gdouble
gst_clock_set_speed (GstClock * clock, gdouble speed)
{
g_return_val_if_fail (GST_IS_CLOCK (clock), 0.0);
GST_WARNING_OBJECT (clock, "called deprecated function");
return 1.0;
}
/**
* gst_clock_get_speed
* @clock: a #GstClock to query
*
* Gets the speed of the given clock.
*
* Returns: the speed of the clock.
*/
gdouble
gst_clock_get_speed (GstClock * clock)
{
g_return_val_if_fail (GST_IS_CLOCK (clock), 0.0);
GST_WARNING_OBJECT (clock, "called deprecated function");
return 1.0;
}
/**
* gst_clock_set_resolution
* @clock: The clock set the resolution on
@ -488,6 +519,8 @@ gst_clock_set_resolution (GstClock * clock, guint64 resolution)
* Get the accuracy of the clock.
*
* Returns: the resolution of the clock in microseconds.
*
* MT safe.
*/
guint64
gst_clock_get_resolution (GstClock * clock)
@ -505,88 +538,31 @@ gst_clock_get_resolution (GstClock * clock)
}
/**
* gst_clock_set_active
* @clock: a #GstClock to set state of
* @active: flag indicating if the clock should be activated (TRUE) or deactivated
* gst_clock_adjust_unlocked
* @clock: a #GstClock to use
* @internal: a clock time
*
* Activates or deactivates the clock based on the active parameter.
* As soon as the clock is activated, the time will start ticking.
*/
void
gst_clock_set_active (GstClock * clock, gboolean active)
{
g_return_if_fail (GST_IS_CLOCK (clock));
GST_ERROR_OBJECT (clock, "called deprecated function that does nothing now.");
return;
}
/**
* gst_clock_is_active
* @clock: a #GstClock to query
* Converts the given @internal clock time to the real time, adjusting
* and making sure that the returned time is increasing.
* This function should be called with the clock lock held.
*
* Checks if the given clock is active.
*
* Returns: TRUE if the clock is active.
*/
gboolean
gst_clock_is_active (GstClock * clock)
{
g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE);
GST_WARNING_OBJECT (clock, "called deprecated function.");
return TRUE;
}
/**
* gst_clock_reset
* @clock: a #GstClock to reset
* Returns: the converted time of the clock.
*
* Reset the clock to time 0.
* MT safe.
*/
void
gst_clock_reset (GstClock * clock)
GstClockTime
gst_clock_adjust_unlocked (GstClock * clock, GstClockTime internal)
{
GstClockTime time = G_GINT64_CONSTANT (0);
GstClockClass *cclass;
GstClockTime ret;
g_return_if_fail (GST_IS_CLOCK (clock));
GST_ERROR_OBJECT (clock, "called deprecated function.");
cclass = GST_CLOCK_GET_CLASS (clock);
if (cclass->get_internal_time) {
time = cclass->get_internal_time (clock);
ret = internal + clock->adjust;
/* make sure the time is increasing, else return last_time */
if ((gint64) ret < (gint64) clock->last_time) {
ret = clock->last_time;
} else {
clock->last_time = ret;
}
GST_LOCK (clock);
//clock->active = FALSE;
clock->start_time = time;
clock->last_time = G_GINT64_CONSTANT (0);
g_list_foreach (clock->entries, (GFunc) gst_clock_reschedule_func, NULL);
GST_UNLOCK (clock);
}
/**
* gst_clock_handle_discont
* @clock: a #GstClock to notify of the discontinuity
* @time: The new time
*
* Notifies the clock of a discontinuity in time.
*
* Returns: TRUE if the clock was updated. It is possible that
* the clock was not updated by this call because only the first
* discontinuitity in the pipeline is honoured.
*/
gboolean
gst_clock_handle_discont (GstClock * clock, guint64 time)
{
GST_ERROR_OBJECT (clock, "called deprecated function.");
return FALSE;
return ret;
}
/**
@ -596,107 +572,60 @@ gst_clock_handle_discont (GstClock * clock, guint64 time)
* Gets the current time of the given clock. The time is always
* monotonically increasing.
*
* Returns: the time of the clock.
* Returns: the time of the clock. Or GST_CLOCK_TIME_NONE when
* giving wrong input.
*
* MT safe.
*/
GstClockTime
gst_clock_get_time (GstClock * clock)
{
GstClockTime ret = G_GINT64_CONSTANT (0);
GstClockTime ret;
GstClockClass *cclass;
g_return_val_if_fail (GST_IS_CLOCK (clock), G_GINT64_CONSTANT (0));
g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_TIME_NONE);
cclass = GST_CLOCK_GET_CLASS (clock);
if (cclass->get_internal_time) {
ret = cclass->get_internal_time (clock) - clock->start_time;
}
/* make sure the time is increasing, else return last_time */
if ((gint64) ret < (gint64) clock->last_time) {
ret = clock->last_time;
ret = cclass->get_internal_time (clock);
} else {
clock->last_time = ret;
ret = G_GINT64_CONSTANT (0);
}
GST_CAT_DEBUG (GST_CAT_CLOCK, "internal time %" GST_TIME_FORMAT,
GST_TIME_ARGS (ret));
GST_LOCK (clock);
ret = gst_clock_adjust_unlocked (clock, ret);
GST_UNLOCK (clock);
GST_CAT_DEBUG (GST_CAT_CLOCK, "adjusted time %" GST_TIME_FORMAT,
GST_TIME_ARGS (ret));
return ret;
}
/**
* gst_clock_get_event_time:
* @clock: clock to query
*
* Gets the "event time" of a given clock. An event on the clock happens
* whenever this function is called. This ensures that multiple events that
* happen shortly after each other are treated as if they happened at the same
* time. GStreamer uses to keep state changes of multiple elements in sync.
* gst_clock_set_time_adjust
* @clock: a #GstClock to adjust
* @adjust: the adjust value
*
* Returns: the time of the event
* Adjusts the current time of the clock with the adjust value.
* A positive value moves the clock forwards and a backwards value
* moves it backwards. Note that _get_time() always returns
* increasing values so when you move the clock backwards, _get_time()
* will report the previous value until the clock catches up.
*
* MT safe.
*/
GstClockTime
gst_clock_get_event_time (GstClock * clock)
void
gst_clock_set_time_adjust (GstClock * clock, GstClockTime adjust)
{
return gst_clock_get_event_time_delay (clock, 0);
}
/**
* gst_clock_get_event_time_delay:
* @clock: clock to query
* @delay: time before the event actually occurs
*
* Gets the "event time" of a given clock. An event on the clock happens
* whenever this function is called. This ensures that multiple events that
* happen shortly after each other are treated as if they happened at the same
* time. GStreamer uses to keep state changes of multiple elements in sync.
*
* When calling this function, the specified delay will be added to the current
* time to produce the event time. This can be used for events that are
* scheduled to happen at some point in the future.
*
* Returns: the time of the event
*/
GstClockTime
gst_clock_get_event_time_delay (GstClock * clock, GstClockTime delay)
{
GstClockTime time;
g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_TIME_NONE);
time = gst_clock_get_time (clock);
if (ABS (GST_CLOCK_DIFF (clock->last_event, time + delay)) <
clock->max_event_diff) {
GST_LOG_OBJECT (clock, "reporting last event time %" G_GUINT64_FORMAT,
clock->last_event);
} else {
clock->last_event = time + delay;
GST_LOG_OBJECT (clock, "reporting new event time %" G_GUINT64_FORMAT,
clock->last_event);
}
return clock->last_event;
}
/**
* 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);
g_return_if_fail (GST_IS_CLOCK (clock));
GST_LOCK (clock);
if (clock->entries)
entry = GST_CLOCK_ENTRY (clock->entries->data);
clock->adjust = adjust;
GST_UNLOCK (clock);
return (GstClockID *) entry;
}
static void
@ -717,14 +646,6 @@ gst_clock_set_property (GObject * object, guint prop_id,
clock->stats = g_value_get_boolean (value);
g_object_notify (object, "stats");
break;
case ARG_MAX_DIFF:
clock->max_diff = g_value_get_int64 (value);
g_object_notify (object, "max-diff");
break;
case ARG_EVENT_DIFF:
clock->max_event_diff = g_value_get_uint64 (value);
g_object_notify (object, "event-diff");
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -743,12 +664,6 @@ gst_clock_get_property (GObject * object, guint prop_id,
case ARG_STATS:
g_value_set_boolean (value, clock->stats);
break;
case ARG_MAX_DIFF:
g_value_set_int64 (value, clock->max_diff);
break;
case ARG_EVENT_DIFF:
g_value_set_uint64 (value, clock->max_event_diff);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;

View file

@ -34,6 +34,7 @@ G_BEGIN_DECLS
#define GST_CLOCK_CLASS(cclass) (G_TYPE_CHECK_CLASS_CAST ((cclass), GST_TYPE_CLOCK, GstClockClass))
#define GST_IS_CLOCK_CLASS(cclass) (G_TYPE_CHECK_CLASS_TYPE ((cclass), GST_TYPE_CLOCK))
#define GST_CLOCK_GET_CLASS(clock) (G_TYPE_INSTANCE_GET_CLASS ((clock), GST_TYPE_CLOCK, GstClockClass))
#define GST_CLOCK_CAST(clock) ((GstClock*)(clock))
typedef guint64 GstClockTime;
typedef gint64 GstClockTimeDiff;
@ -55,6 +56,21 @@ G_STMT_START { \
(tv).tv_usec = ((t) - (tv).tv_sec * GST_SECOND) / GST_USECOND; \
} G_STMT_END
#define GST_TIMESPEC_TO_TIME(ts) ((ts).tv_sec * GST_SECOND + (ts).tv_nsec * GST_NSECOND)
#define GST_TIME_TO_TIMESPEC(t,ts) \
G_STMT_START { \
(ts).tv_sec = (t) / GST_SECOND; \
(ts).tv_usec = ((t) - (ts).tv_sec * GST_SECOND) / GST_NSECOND; \
} G_STMT_END
/* timestamp debugging macros */
#define GST_TIME_FORMAT "u:%02u:%02u.%09u"
#define GST_TIME_ARGS(t) \
(guint) ((t) / (GST_SECOND * 60 * 60)), \
(guint) (((t) / (GST_SECOND * 60)) % 60), \
(guint) (((t) / GST_SECOND) % 60), \
(guint) ((t) % GST_SECOND)
#define GST_CLOCK_ENTRY_TRACE_NAME "GstClockEntry"
typedef struct _GstClockEntry GstClockEntry;
@ -65,15 +81,18 @@ typedef struct _GstClockClass GstClockClass;
typedef gboolean (*GstClockCallback) (GstClock *clock, GstClockTime time,
GstClockID id, gpointer user_data);
typedef enum {
/* --- protected --- */
GST_CLOCK_ENTRY_OK,
GST_CLOCK_ENTRY_EARLY,
GST_CLOCK_ENTRY_RESTART
} GstClockEntryStatus;
typedef enum
{
GST_CLOCK_OK = 0,
GST_CLOCK_EARLY = 1,
GST_CLOCK_UNSCHEDULED = 2,
GST_CLOCK_BUSY = 3,
GST_CLOCK_BADTIME = 4,
GST_CLOCK_ERROR = 5,
GST_CLOCK_UNSUPPORTED = 6,
} GstClockReturn;
typedef enum {
/* --- protected --- */
GST_CLOCK_ENTRY_SINGLE,
GST_CLOCK_ENTRY_PERIODIC
} GstClockEntryType;
@ -86,25 +105,17 @@ typedef enum {
#define GST_CLOCK_ENTRY_STATUS(entry) ((entry)->status)
struct _GstClockEntry {
/* --- protected --- */
GstAtomicInt refcount;
/*< protected >*/
GstClock *clock;
GstClockEntryType type;
GstClockTime time;
GstClockTime interval;
GstClockEntryStatus status;
GstClockReturn status;
GstClockCallback func;
gpointer user_data;
};
typedef enum
{
GST_CLOCK_STOPPED = 0,
GST_CLOCK_TIMEOUT = 1,
GST_CLOCK_EARLY = 2,
GST_CLOCK_ERROR = 3,
GST_CLOCK_UNSUPPORTED = 4
} GstClockReturn;
typedef enum
{
GST_CLOCK_FLAG_CAN_DO_SINGLE_SYNC = (1 << 1),
@ -112,41 +123,39 @@ typedef enum
GST_CLOCK_FLAG_CAN_DO_PERIODIC_SYNC = (1 << 3),
GST_CLOCK_FLAG_CAN_DO_PERIODIC_ASYNC = (1 << 4),
GST_CLOCK_FLAG_CAN_SET_RESOLUTION = (1 << 5),
GST_CLOCK_FLAG_CAN_SET_SPEED = (1 << 6)
} GstClockFlags;
#define GST_CLOCK_FLAGS(clock) (GST_CLOCK(clock)->flags)
#define GST_CLOCK_COND(clock) (GST_CLOCK_CAST(clock)->entries_changed)
#define GST_CLOCK_WAIT(clock) g_cond_wait(GST_CLOCK_COND(clock),GST_GET_LOCK(clock))
#define GST_CLOCK_TIMED_WAIT(clock,tv) g_cond_timed_wait(GST_CLOCK_COND(clock),GST_GET_LOCK(clock),tv)
#define GST_CLOCK_SIGNAL(clock) g_cond_broadcast(GST_CLOCK_COND(clock))
struct _GstClock {
GstObject object;
/*< public >*/
GstClockFlags flags;
/* --- protected --- */
GstClockTime start_time;
/*< protected >*/ /* with LOCK */
GstClockTime adjust;
GstClockTime last_time;
gint64 max_diff;
/* --- private --- */
guint64 resolution;
GList *entries;
GMutex *active_mutex;
GCond *active_cond;
GCond *entries_changed;
/*< private >*/
guint64 resolution;
gboolean stats;
GstClockTime last_event;
GstClockTime max_event_diff;
gpointer _gst_reserved[GST_PADDING];
};
struct _GstClockClass {
GstObjectClass parent_class;
/*< protected >*/
/* vtable */
gdouble (*change_speed) (GstClock *clock,
gdouble oldspeed, gdouble newspeed);
gdouble (*get_speed) (GstClock *clock);
guint64 (*change_resolution) (GstClock *clock, guint64 old_resolution,
guint64 new_resolution);
guint64 (*get_resolution) (GstClock *clock);
@ -154,32 +163,24 @@ struct _GstClockClass {
GstClockTime (*get_internal_time) (GstClock *clock);
/* waiting on an ID */
GstClockEntryStatus (*wait) (GstClock *clock, GstClockEntry *entry);
GstClockEntryStatus (*wait_async) (GstClock *clock, GstClockEntry *entry);
GstClockReturn (*wait) (GstClock *clock, GstClockEntry *entry);
GstClockReturn (*wait_async) (GstClock *clock, GstClockEntry *entry);
void (*unschedule) (GstClock *clock, GstClockEntry *entry);
void (*unlock) (GstClock *clock, GstClockEntry *entry);
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
GType gst_clock_get_type (void);
gdouble gst_clock_set_speed (GstClock *clock, gdouble speed);
gdouble gst_clock_get_speed (GstClock *clock);
guint64 gst_clock_set_resolution (GstClock *clock, guint64 resolution);
guint64 gst_clock_get_resolution (GstClock *clock);
void gst_clock_set_active (GstClock *clock, gboolean active);
gboolean gst_clock_is_active (GstClock *clock);
void gst_clock_reset (GstClock *clock);
gboolean gst_clock_handle_discont (GstClock *clock, guint64 time);
GstClockTime gst_clock_get_time (GstClock *clock);
GstClockTime gst_clock_get_event_time (GstClock *clock);
GstClockTime gst_clock_get_event_time_delay (GstClock *clock, GstClockTime delay);
void gst_clock_set_time_adjust (GstClock *clock, GstClockTime adjust);
GstClockTime gst_clock_adjust_unlocked (GstClock *clock, GstClockTime internal);
GstClockID gst_clock_get_next_id (GstClock *clock);
/* creating IDs that can be used to get notifications */
GstClockID gst_clock_new_single_shot_id (GstClock *clock,
@ -188,7 +189,13 @@ GstClockID gst_clock_new_periodic_id (GstClock *clock,
GstClockTime start_time,
GstClockTime interval);
/* reference counting */
GstClockID gst_clock_id_ref (GstClockID id);
void gst_clock_id_unref (GstClockID id);
/* operations on IDs */
gint gst_clock_id_compare_func (gconstpointer id1, gconstpointer id2);
GstClockTime gst_clock_id_get_time (GstClockID id);
GstClockReturn gst_clock_id_wait (GstClockID id,
GstClockTimeDiff *jitter);
@ -196,9 +203,6 @@ GstClockReturn gst_clock_id_wait_async (GstClockID id,
GstClockCallback func,
gpointer user_data);
void gst_clock_id_unschedule (GstClockID id);
void gst_clock_id_unlock (GstClockID id);
void gst_clock_id_free (GstClockID id);
G_END_DECLS

View file

@ -1,6 +1,6 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* 2004 Wim Taymans <wim@fluendo.com>
*
* gstcompat.h: backwards compatibility stuff
*
@ -28,57 +28,6 @@
G_BEGIN_DECLS
#ifndef GST_DISABLE_DEPRECATED
/* 0.5.2 changes; remove these ASAP */
/* element functions */
#define gst_element_connect(a,b) gst_element_link(a,b)
#define gst_element_connect_pads(a,b,c,d) \
gst_element_link_pads(a,b,c,d)
#ifdef G_HAVE_ISO_VARARGS
#define gst_element_connect_many(a,...) gst_element_link_many(a,__VA_ARGS__)
#elif defined(G_HAVE_GNUC_VARARGS)
#define gst_element_connect_many(a,args...) \
gst_element_link_many(a, ## args)
#else
/* FIXME: need an inline function */
#endif
#define gst_element_connect_filtered(a,b,c) \
gst_element_link_filtered(a,b,c)
#define gst_element_disconnect(a,b) gst_element_unlink(a,b)
/* pad functions */
#define gst_pad_connect(a,b) gst_pad_link(a,b)
#define gst_pad_connect_filtered(a,b,c) gst_pad_link_filtered(a,b,c)
#define gst_pad_disconnect(a,b) gst_pad_unlink(a,b)
#define gst_pad_proxy_connect(a,b) gst_pad_proxy_link(a,b)
#define gst_pad_set_connect_function(a,b) \
gst_pad_set_link_function(a,b)
/* pad macros */
#define GST_PAD_IS_CONNECTED(a) GST_PAD_IS_LINKED(a)
/* pad enums */
#define GST_PAD_CONNECT_REFUSED GST_PAD_LINK_REFUSED
#define GST_PAD_CONNECT_DELAYED GST_PAD_LINK_DELAYED
#define GST_PAD_CONNECT_OK GST_PAD_LINK_OK
#define GST_PAD_CONNECT_DONE GST_PAD_LINK_DONE
typedef GstPadLinkReturn GstPadConnectReturn;
/* pad function types */
typedef GstPadLinkFunction GstPadConnectFunction;
/* probably not used */
/*
* GST_RPAD_LINKFUNC
*/
/* 0.8.1.1 removal; remove completely in 0.9 */
/* information messages */
# ifdef G_HAVE_ISO_VARARGS
#define gst_info(...) GST_INFO(__VA_ARGS__)
# elif defined(G_HAVE_GNUC_VARARGS)
#define gst_info(format,args...) GST_INFO(format,##args)
# endif
#endif /* not GST_DISABLE_DEPRECATED */

View file

@ -28,6 +28,7 @@
#include "gstcpu.h"
#include "gstinfo.h"
static GStaticMutex _cpu_mutex = G_STATIC_MUTEX_INIT;
static guint32 _gst_cpu_flags = 0;
#if defined(HAVE_CPU_I386) && defined(__GNUC__)
@ -89,7 +90,9 @@ _gst_cpu_initialize_i386 (gulong * flags, GString * featurelist)
{
gboolean AMD;
gulong eax = 0, ebx = 0, ecx = 0, edx = 0;
gboolean res = FALSE;
g_static_mutex_lock (&_cpu_mutex);
gst_cpuid_i386 (0, &eax, &ebx, &ecx, &edx);
AMD = (ebx == 0x68747541) && (ecx == 0x444d4163) && (edx == 0x69746e65);
@ -124,13 +127,21 @@ _gst_cpu_initialize_i386 (gulong * flags, GString * featurelist)
}
*flags = eax;
if (_gst_cpu_flags)
return TRUE;
return FALSE;
res = TRUE;
g_static_mutex_unlock (&_cpu_mutex);
return res;
}
#endif
GstCPUFlags
gst_cpu_get_flags (void)
{
return _gst_cpu_flags;
GstCPUFlags res;
g_static_mutex_lock (&_cpu_mutex);
res = _gst_cpu_flags;
g_static_mutex_unlock (&_cpu_mutex);
return res;
}

View file

@ -1,6 +1,6 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* 2000 Wim Taymans <wim@fluendo.com>
*
* gstdata.c: Data operations
*
@ -43,11 +43,12 @@ gst_data_get_type (void)
* @data: a #GstData to initialize
* @type: the type of this data
* @flags: flags for this data
* @free: a free function
* @copy: a copy function
* @free: a free function
* @copy: a copy function
*
* Initialize the given data structure with the given parameters. The free and copy
* function will be called when this data is freed or copied respectively.
* Initialize the given data structure with the given parameters.
* The free and copy function will be called when this data is freed
* or copied, respectively.
*/
void
gst_data_init (GstData * data, GType type, guint16 flags,
@ -64,7 +65,7 @@ gst_data_init (GstData * data, GType type, guint16 flags,
* @target: the target #GstData to copy into
*
* Copy the GstData into the specified target GstData structure.
* Thos method is mainly used by subclasses when they want to copy
* This method is mainly used by subclasses when they want to copy
* the relevant GstData info.
*/
void
@ -77,7 +78,7 @@ gst_data_copy_into (const GstData * data, GstData * target)
* gst_data_dispose:
* @data: a #GstData to dispose
*
* Free all the resources allocated in the gst_data_init() function,
* Free all the resources allocated in the gst_data_init() function,
* mainly used by subclass implementors.
*/
void
@ -95,9 +96,11 @@ gst_data_dispose (GstData * data)
* Copies the given #GstData. This function will call the custom subclass
* copy function or return NULL if no function was provided by the subclass.
*
* Returns: a copy of the data or NULL if the data cannot be copied. The refcount
* of the original buffer is not changed so you should unref it when you don't
* need it anymore.
* Returns: a copy of the data or NULL if the data cannot be copied.
* The refcount of the original buffer is not changed so you should unref it
* when you don't need it anymore.
*
* MT safe.
*/
GstData *
gst_data_copy (const GstData * data)
@ -112,12 +115,14 @@ gst_data_copy (const GstData * data)
/**
* gst_data_is_writable:
* @data: a #GstData to copy
* @data: a #GstData to check
*
* Query if the gstdata needs to be copied before it can safely be modified.
* Query if the data needs to be copied before it can safely be modified.
*
* Returns: FALSE if the given #GstData is potentially shared and needs to
* be copied before it can be modified safely.
*
* MT safe.
*/
gboolean
gst_data_is_writable (GstData * data)
@ -128,12 +133,12 @@ gst_data_is_writable (GstData * data)
refcount = gst_atomic_int_read (&data->refcount);
if (refcount > 1)
return FALSE;
if (GST_DATA_FLAG_IS_SET (data, GST_DATA_READONLY))
return FALSE;
/* if we have the only ref and the data is not readonly, we can
* safely write */
if (refcount == 1 && !GST_DATA_FLAG_IS_SET (data, GST_DATA_READONLY))
return TRUE;
return TRUE;
return FALSE;
}
/**
@ -143,11 +148,14 @@ gst_data_is_writable (GstData * data)
* Copies the given #GstData if the refcount is greater than 1 so that the
* #GstData object can be written to safely.
*
* Returns: a copy of the data if the refcount is > 1 or the buffer is
* Returns: a copy of the data if the refcount is > 1 or the buffer is
* marked READONLY, data if the refcount == 1,
* or NULL if the data could not be copied. The refcount of the original buffer
* is decreased when a copy is made, so you are not supposed to use it after a
* call to this function.
* or NULL if the data could not be copied.
*
* The refcount of the passed @data is decreased when a copy is made, so
* you are not supposed to use it anymore after a call to this function.
*
* MT safe.
*/
GstData *
gst_data_copy_on_write (GstData * data)
@ -158,6 +166,8 @@ gst_data_copy_on_write (GstData * data)
refcount = gst_atomic_int_read (&data->refcount);
/* if we have the only ref and the data is not readonly, we can
* safely write, so we return the input data */
if (refcount == 1 && !GST_DATA_FLAG_IS_SET (data, GST_DATA_READONLY))
return GST_DATA (data);
@ -178,6 +188,8 @@ gst_data_copy_on_write (GstData * data)
* Increments the reference count of this data.
*
* Returns: the data
*
* MT safe.
*/
GstData *
gst_data_ref (GstData * data)
@ -201,6 +213,8 @@ gst_data_ref (GstData * data)
* Increments the reference count of this data by the given number.
*
* Returns: the data
*
* MT safe.
*/
GstData *
gst_data_ref_by_count (GstData * data, gint count)
@ -224,9 +238,12 @@ gst_data_ref_by_count (GstData * data, gint count)
* Decrements the refcount of this data. If the refcount is
* zero, the data will be freed.
*
* When you add data to a pipeline, the pipeline takes ownership of the
* data. When the data has been used by some plugin, it must unref()s it.
* Applications usually don't need to unref() anything.
* When you move data out of your element into the pipeline,
* the pipeline takes ownership of the
* data. When the data has been consumed by some element, it must unref() it.
* Applications usually don't need to unref() @data.
*
* MT safe.
*/
void
gst_data_unref (GstData * data)

View file

@ -39,22 +39,22 @@ G_BEGIN_DECLS
#define GST_DATA_FLAG_SHIFT(flag) (1<<(flag))
#define GST_DATA_FLAG_IS_SET(data,flag) (GST_DATA_FLAGS(data) & (1<<(flag)))
#define GST_DATA_FLAG_SET(data,flag) G_STMT_START{ (GST_DATA_FLAGS(data) |= (1<<(flag))); }G_STMT_END
#define GST_DATA_FLAG_UNSET(data,flag) G_STMT_START{ (GST_DATA_FLAGS(data) &= ~(1<<(flag))); }G_STMT_END
#define GST_DATA_FLAG_UNSET(data,flag) G_STMT_START{ (GST_DATA_FLAGS(data) &= ~(1<<(flag))); }G_STMT_END
/* Macros for the GType */
#define GST_TYPE_DATA (gst_data_get_type ())
typedef struct _GstData GstData;
typedef void (*GstDataFreeFunction) (GstData *data);
typedef void (*GstDataFreeFunction) (GstData *data);
typedef GstData* (*GstDataCopyFunction) (const GstData *data);
typedef enum
{
GST_DATA_READONLY = 1,
GST_DATA_READONLY = 1,
/* insert more */
GST_DATA_FLAG_LAST = 8
GST_DATA_FLAG_LAST = 8
} GstDataFlags;
/* refcount */
@ -62,22 +62,25 @@ typedef enum
#define GST_DATA_REFCOUNT_VALUE(data) (gst_atomic_int_read (&(GST_DATA(data))->refcount))
/* copy/free functions */
#define GST_DATA_COPY_FUNC(data) (GST_DATA(data)->copy)
#define GST_DATA_FREE_FUNC(data) (GST_DATA(data)->free)
#define GST_DATA_COPY_FUNC(data) (GST_DATA(data)->copy)
#define GST_DATA_FREE_FUNC(data) (GST_DATA(data)->free)
struct _GstData {
GType type;
GType type;
/*< public >*/ /* with COW */
/* refcounting */
GstAtomicInt refcount;
guint16 flags;
/*< protected >*/
/* utility function pointers, can override default */
GstDataFreeFunction free; /* free the data */
GstDataCopyFunction copy; /* copy the data */
GstDataFreeFunction free; /* free the data */
GstDataCopyFunction copy; /* copy the data */
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
@ -89,9 +92,9 @@ void gst_data_dispose (GstData *data);
void gst_data_copy_into (const GstData *data, GstData *target);
/* basic operations on data */
GstData* gst_data_copy (const GstData *data);
gboolean gst_data_is_writable (GstData *data);
GstData* gst_data_copy_on_write (GstData *data);
GstData* gst_data_copy (const GstData *data);
gboolean gst_data_is_writable (GstData *data);
GstData* gst_data_copy_on_write (GstData *data);
/* reference counting */
GstData* gst_data_ref (GstData* data);

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,7 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* 2004 Wim Taymans <wim@fluendo.com>
*
* gstelement.h: Header for GstElement
*
@ -32,6 +33,7 @@
#include <gst/gstplugin.h>
#include <gst/gstpluginfeature.h>
#include <gst/gstindex.h>
#include <gst/gstiterator.h>
#include <gst/gsttag.h>
G_BEGIN_DECLS
@ -39,14 +41,18 @@ G_BEGIN_DECLS
typedef struct _GstElementDetails GstElementDetails;
/* FIXME: need translatable stuff in here (how handle in registry)? */
struct _GstElementDetails {
struct _GstElementDetails
{
/*< public > */
gchar *longname; /* long, english name */
gchar *klass; /* type of element, as hierarchy */
gchar *description; /* insights of one form or another */
gchar *author; /* who wrote this thing? */
/*< private > */
gpointer _gst_reserved[GST_PADDING];
};
#define GST_ELEMENT_DETAILS(longname,klass,description,author) \
{ longname, klass, description, author, GST_PADDING_INIT }
#define GST_IS_ELEMENT_DETAILS(details) ( \
@ -60,6 +66,7 @@ struct _GstElementDetails {
*/
#define GST_STATE(obj) (GST_ELEMENT(obj)->current_state)
#define GST_STATE_PENDING(obj) (GST_ELEMENT(obj)->pending_state)
#define GST_STATE_ERROR(obj) (GST_ELEMENT(obj)->state_error)
/* Note: using 8 bit shift mostly "just because", it leaves us enough room to grow <g> */
#define GST_STATE_TRANSITION(obj) ((GST_STATE(obj)<<8) | GST_STATE_PENDING(obj))
@ -78,6 +85,7 @@ GST_EXPORT GType _gst_element_type;
#define GST_ELEMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_ELEMENT, GstElementClass))
#define GST_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_ELEMENT, GstElement))
#define GST_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_ELEMENT, GstElementClass))
#define GST_ELEMENT_CAST(obj) ((GstElement*)(obj))
/* convenience functions */
#ifndef GST_DISABLE_DEPRECATED
@ -98,14 +106,11 @@ GST_EXPORT GType _gst_element_type;
#endif
#endif
typedef enum {
/* element is complex (for some def.) and generally require a cothread */
GST_ELEMENT_COMPLEX = GST_OBJECT_FLAG_LAST,
typedef enum
{
/* input and output pads aren't directly coupled to each other
examples: queues, multi-output async readers, etc. */
GST_ELEMENT_DECOUPLED,
/* this element should be placed in a thread if at all possible */
GST_ELEMENT_THREAD_SUGGESTED,
/* this element, for some reason, has a loop function that performs
* an infinite loop without calls to gst_element_yield () */
GST_ELEMENT_INFINITE_LOOP,
@ -116,6 +121,7 @@ typedef enum {
/* use threadsafe property get/set implementation */
GST_ELEMENT_USE_THREADSAFE_PROPERTIES,
/* private flags that can be used by the scheduler */
GST_ELEMENT_SCHEDULER_PRIVATE1,
GST_ELEMENT_SCHEDULER_PRIVATE2,
@ -136,7 +142,7 @@ typedef enum {
#define GST_ELEMENT_NAME(obj) (GST_OBJECT_NAME(obj))
#define GST_ELEMENT_PARENT(obj) (GST_OBJECT_PARENT(obj))
#define GST_ELEMENT_SCHED(obj) (((GstElement*)(obj))->sched)
#define GST_ELEMENT_SCHEDULER(obj) (((GstElement*)(obj))->sched)
#define GST_ELEMENT_CLOCK(obj) (((GstElement*)(obj))->clock)
#define GST_ELEMENT_PADS(obj) ((obj)->pads)
@ -186,11 +192,15 @@ struct _GstElement {
GstClock *clock;
GstClockTimeDiff base_time; /* NULL/READY: 0 - PAUSED: current time - PLAYING: difference to clock */
/* element pads */
guint16 numpads;
guint16 numsrcpads;
guint16 numsinkpads;
GList *pads;
/* element pads, these lists can only be iterated while holding
* the LOCK or checking the cookie after each LOCK. */
guint16 numpads;
GList *pads;
guint16 numsrcpads;
GList *srcpads;
guint16 numsinkpads;
GList *sinkpads;
guint32 pads_cookie;
GMutex *state_mutex;
GCond *state_cond;
@ -203,9 +213,11 @@ struct _GstElement {
gpointer _gst_reserved[GST_PADDING];
};
struct _GstElementClass {
GstObjectClass parent_class;
struct _GstElementClass
{
GstObjectClass parent_class;
/*< public > */
/* the element details */
GstElementDetails details;
@ -213,9 +225,10 @@ struct _GstElementClass {
GstElementFactory *elementfactory;
/* templates for our pads */
GList *padtemplates;
gint numpadtemplates;
GList *padtemplates;
gint numpadtemplates;
guint32 pad_templ_cookie;
/* signal callbacks */
void (*state_change) (GstElement *element, GstElementState old, GstElementState state);
void (*new_pad) (GstElement *element, GstPad *pad);
@ -257,6 +270,9 @@ struct _GstElementClass {
GstIndex* (*get_index) (GstElement *element);
void (*set_index) (GstElement *element, GstIndex *index);
/* scheduler */
void (*set_scheduler) (GstElement *element, GstScheduler *scheduler);
GstElementStateReturn (*set_state) (GstElement *element, GstElementState state);
/* FIXME 0.9: move up to signals */
@ -327,12 +343,9 @@ gboolean gst_element_interrupt (GstElement *element);
void gst_element_set_scheduler (GstElement *element, GstScheduler *sched);
GstScheduler* gst_element_get_scheduler (GstElement *element);
void gst_element_add_pad (GstElement *element, GstPad *pad);
void gst_element_remove_pad (GstElement *element, GstPad *pad);
gboolean gst_element_add_pad (GstElement *element, GstPad *pad);
gboolean gst_element_remove_pad (GstElement *element, GstPad *pad);
GstPad * gst_element_add_ghost_pad (GstElement *element, GstPad *pad, const gchar *name);
#ifndef GST_DISABLE_DEPRECATED
void gst_element_remove_ghost_pad (GstElement *element, GstPad *pad);
#endif
void gst_element_no_more_pads (GstElement *element);
GstPad* gst_element_get_pad (GstElement *element, const gchar *name);
@ -340,8 +353,8 @@ GstPad* gst_element_get_static_pad (GstElement *element, const gchar *name);
GstPad* gst_element_get_request_pad (GstElement *element, const gchar *name);
void gst_element_release_request_pad (GstElement *element, GstPad *pad);
G_CONST_RETURN GList*
gst_element_get_pad_list (GstElement *element);
GstIterator *gst_element_iterate_pads (GstElement * element);
GstPad* gst_element_get_compatible_pad (GstElement *element, GstPad *pad);
GstPad* gst_element_get_compatible_pad_filtered (GstElement *element, GstPad *pad,
const GstCaps *filtercaps);
@ -396,7 +409,7 @@ void gst_element_error_full (GstElement *element, GQuark domain, gint code,
const gchar *file, const gchar *function, gint line);
gboolean gst_element_is_locked_state (GstElement *element);
void gst_element_set_locked_state (GstElement *element, gboolean locked_state);
gboolean gst_element_set_locked_state (GstElement *element, gboolean locked_state);
gboolean gst_element_sync_state_with_parent (GstElement *element);
GstElementState gst_element_get_state (GstElement *element);

View file

@ -161,6 +161,7 @@ typedef struct
struct _GstEvent {
GstData data;
/*< public >*/ /* with COW */
GstEventType type;
guint64 timestamp;
GstObject *src;
@ -189,6 +190,7 @@ struct _GstEvent {
} structure;
} event_data;
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};

View file

@ -1,6 +1,7 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wim.taymans@chello.be>
* 2005 Wim Taymans <wim@fluendo.com>
*
* gstformat.c: GstFormat registration
*
@ -25,10 +26,11 @@
#include "gst_private.h"
#include "gstformat.h"
static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
static GList *_gst_formats = NULL;
static GHashTable *_nick_to_format = NULL;
static GHashTable *_format_to_nick = NULL;
static gint _n_values = 1; /* we start from 1 because 0 reserved for UNDEFINED */
static guint32 _n_values = 1; /* we start from 1 because 0 reserved for UNDEFINED */
static GstFormatDefinition standard_definitions[] = {
{GST_FORMAT_DEFAULT, "default", "Default format for the media type"},
@ -44,6 +46,7 @@ _gst_format_initialize (void)
{
GstFormatDefinition *standards = standard_definitions;
g_static_mutex_lock (&mutex);
if (_nick_to_format == NULL) {
_nick_to_format = g_hash_table_new (g_str_hash, g_str_equal);
_format_to_nick = g_hash_table_new (NULL, NULL);
@ -58,6 +61,7 @@ _gst_format_initialize (void)
standards++;
_n_values++;
}
g_static_mutex_unlock (&mutex);
}
/**
@ -66,10 +70,12 @@ _gst_format_initialize (void)
* @description: The description of the new format
*
* Create a new GstFormat based on the nick or return an
* allrady registered format with that nick
* already registered format with that nick.
*
* Returns: A new GstFormat or an already registered format
* with the same nick.
*
* MT safe.
*/
GstFormat
gst_format_register (const gchar * nick, const gchar * description)
@ -89,11 +95,13 @@ gst_format_register (const gchar * nick, const gchar * description)
format->nick = g_strdup (nick);
format->description = g_strdup (description);
g_static_mutex_lock (&mutex);
g_hash_table_insert (_nick_to_format, format->nick, format);
g_hash_table_insert (_format_to_nick, GINT_TO_POINTER (format->value),
format);
_gst_formats = g_list_append (_gst_formats, format);
_n_values++;
g_static_mutex_unlock (&mutex);
return format->value;
}
@ -114,7 +122,9 @@ gst_format_get_by_nick (const gchar * nick)
g_return_val_if_fail (nick != NULL, 0);
g_static_mutex_lock (&mutex);
format = g_hash_table_lookup (_nick_to_format, nick);
g_static_mutex_unlock (&mutex);
if (format != NULL)
return format->value;
@ -154,22 +164,38 @@ gst_formats_contains (const GstFormat * formats, GstFormat format)
* Get details about the given format.
*
* Returns: The #GstFormatDefinition for @format or NULL on failure.
*
* MT safe.
*/
const GstFormatDefinition *
gst_format_get_details (GstFormat format)
{
return g_hash_table_lookup (_format_to_nick, GINT_TO_POINTER (format));
const GstFormatDefinition *result;
g_static_mutex_lock (&mutex);
result = g_hash_table_lookup (_format_to_nick, GINT_TO_POINTER (format));
g_static_mutex_unlock (&mutex);
return result;
}
/**
* gst_format_get_definitions:
* gst_format_iterate_definitions:
*
* Get a list of all the registered formats.
* Iterate all the registered formats. The format definition is read
* only.
*
* Returns: A GList of #GstFormatDefinition.
* Returns: A GstIterator of #GstFormatDefinition.
*/
const GList *
gst_format_get_definitions (void)
GstIterator *
gst_format_iterate_definitions (void)
{
return _gst_formats;
GstIterator *result;
g_static_mutex_lock (&mutex);
result = gst_iterator_new_list (g_static_mutex_get_mutex (&mutex),
&_n_values, &_gst_formats, NULL, NULL, NULL);
g_static_mutex_unlock (&mutex);
return result;
}

View file

@ -27,6 +27,8 @@
#include <glib.h>
#include <gst/gstiterator.h>
G_BEGIN_DECLS
typedef enum {
@ -88,8 +90,7 @@ gboolean gst_formats_contains (const GstFormat *formats, GstFormat format);
/* query for format details */
G_CONST_RETURN GstFormatDefinition*
gst_format_get_details (GstFormat format);
G_CONST_RETURN GList*
gst_format_get_definitions (void);
GstIterator* gst_format_iterate_definitions (void);
G_END_DECLS

View file

@ -515,7 +515,8 @@ gst_index_gtype_resolver (GstIndex * index, GstObject * writer,
gchar ** writer_string, gpointer data)
{
if (GST_IS_PAD (writer)) {
GstElement *element = gst_pad_get_parent (GST_PAD (writer));
GstElement *element =
(GstElement *) gst_object_get_parent (GST_OBJECT (writer));
*writer_string = g_strdup_printf ("%s.%s",
g_type_name (G_OBJECT_TYPE (element)), gst_object_get_name (writer));

View file

@ -41,6 +41,7 @@
#include "gstpad.h"
#include "gstscheduler.h"
#include "gst_private.h"
#include "gstatomic_impl.h"
#ifdef HAVE_VALGRIND
#include <valgrind/valgrind.h>
#endif

View file

@ -109,6 +109,7 @@ struct _GstDebugCategory {
#define GST_STR_NULL(str) ((str) ? (str) : "(NULL)")
/* easier debugging for pad names */
/* FIXME, not MT safe */
#define GST_DEBUG_PAD_NAME(pad) \
(GST_OBJECT_PARENT(pad) != NULL) ? \
GST_STR_NULL (GST_OBJECT_NAME (GST_OBJECT_PARENT(pad))) : \
@ -824,15 +825,6 @@ GST_LOG (const char *format, ...)
void gst_debug_print_stack_trace (void);
/* timestamp debugging macros */
/* FIXME 0.9: move into the correct header (gstclock.h) */
#define GST_TIME_FORMAT "u:%02u:%02u.%09u"
#define GST_TIME_ARGS(t) \
(guint) ((t) / (GST_SECOND * 60 * 60)), \
(guint) (((t) / (GST_SECOND * 60)) % 60), \
(guint) (((t) / GST_SECOND) % 60), \
(guint) ((t) % GST_SECOND)
G_END_DECLS
#endif /* __GSTINFO_H__ */

View file

@ -1,5 +1,9 @@
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* <2005> Wim Taymans <wim@fluendo.com>
*
* gstmemchunk.c: implementation of lockfree allocation of fixed
* size memory chunks.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -28,7 +32,6 @@
#include <valgrind/valgrind.h>
#endif
#define GST_MEM_CHUNK_AREA(chunk) (((GstMemChunkElement*)(chunk))->area)
#define GST_MEM_CHUNK_DATA(chunk) ((gpointer)(((GstMemChunkElement*)(chunk)) + 1))
#define GST_MEM_CHUNK_LINK(mem) ((GstMemChunkElement*)((guint8*)(mem) - sizeof (GstMemChunkElement)))
@ -105,6 +108,8 @@ populate (GstMemChunk * mem_chunk)
* when it is too small (with a small overhead when that happens)
*
* Returns: a new #GstMemChunk
*
* MT safe.
*/
GstMemChunk *
gst_mem_chunk_new (gchar * name, gint atom_size, gulong area_size, gint type)
@ -152,7 +157,9 @@ free_area (gpointer key, gpointer value, gpointer user_data)
* gst_mem_chunk_destroy:
* @mem_chunk: the GstMemChunk to destroy
*
* Free the memory allocated by the memchunk
* Free the memory allocated by the memchunk. This function
* is not Threadsafe as it does not wait for all outstanding
* allocations to be freed.
*/
void
gst_mem_chunk_destroy (GstMemChunk * mem_chunk)
@ -186,6 +193,8 @@ gst_mem_chunk_destroy (GstMemChunk * mem_chunk)
* was created.
*
* Returns: a pointer to the allocated memory region.
*
* MT safe.
*/
gpointer
gst_mem_chunk_alloc (GstMemChunk * mem_chunk)
@ -197,15 +206,20 @@ gst_mem_chunk_alloc (GstMemChunk * mem_chunk)
again:
chunk = gst_trash_stack_pop (&mem_chunk->stack);
/* chunk is empty, try to refill */
if (!chunk) {
if (populate (mem_chunk))
if (G_UNLIKELY (!chunk)) {
if (G_LIKELY (populate (mem_chunk))) {
goto again;
else
} else {
/* this happens when we are in cleanup mode and we
* allocate all remaining chunks for cleanup */
return NULL;
}
}
#ifdef HAVE_VALGRIND
VALGRIND_MALLOCLIKE_BLOCK (GST_MEM_CHUNK_DATA (chunk), mem_chunk->atom_size,
0, 0);
if (G_UNLIKELY (__gst_in_valgrind ())) {
VALGRIND_MALLOCLIKE_BLOCK (GST_MEM_CHUNK_DATA (chunk), mem_chunk->atom_size,
0, 0);
}
#endif
return GST_MEM_CHUNK_DATA (chunk);
}
@ -219,13 +233,15 @@ again:
* was created. The memory will be set to all zeroes.
*
* Returns: a pointer to the allocated memory region.
*
* MT safe.
*/
gpointer
gst_mem_chunk_alloc0 (GstMemChunk * mem_chunk)
{
gpointer mem = gst_mem_chunk_alloc (mem_chunk);
if (mem)
if (G_LIKELY (mem))
memset (mem, 0, mem_chunk->atom_size);
return mem;
@ -237,6 +253,8 @@ gst_mem_chunk_alloc0 (GstMemChunk * mem_chunk)
* @mem: the memory region to hand back to the chunk
*
* Free the memeory region allocated from the chunk.
*
* MT safe.
*/
void
gst_mem_chunk_free (GstMemChunk * mem_chunk, gpointer mem)
@ -249,7 +267,9 @@ gst_mem_chunk_free (GstMemChunk * mem_chunk, gpointer mem)
chunk = GST_MEM_CHUNK_LINK (mem);
#ifdef HAVE_VALGRIND
VALGRIND_FREELIKE_BLOCK (mem, 0);
if (G_UNLIKELY (__gst_in_valgrind ())) {
VALGRIND_FREELIKE_BLOCK (mem, 0);
}
#endif
gst_trash_stack_push (&mem_chunk->stack, chunk);
}

View file

@ -1,6 +1,7 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* 2005 Wim Taymans <wim@fluendo.com>
*
* gstobject.c: Fundamental class used for all of GStreamer
*
@ -25,11 +26,32 @@
#include "gstobject.h"
#include "gstmarshal.h"
#include "gstinfo.h"
#include "gstatomic_impl.h"
#ifndef GST_DISABLE_TRACE
#include "gsttrace.h"
#endif
#define DEBUG_REFCOUNT
#define REFCOUNT_HACK
/* Refcount hack: since glib is not threadsafe, the glib refcounter can be
* screwed up and the object can be freed unexpectedly. We use an evil hack
* to work around this problem. We set the glib refcount to a high value so
* that glib will never unref the object under realistic circumstances. Then
* we use our own atomic refcounting to do proper MT safe refcounting.
*
* A proper fix is of course to make the glib refcounting threadsafe which is
* planned.
*/
#ifdef REFCOUNT_HACK
#define PATCH_REFCOUNT(obj) ((GObject*)(obj))->ref_count = 100000;
#define PATCH_REFCOUNT1(obj) ((GObject*)(obj))->ref_count = 1;
#else
#define PATCH_REFCOUNT(obj)
#define PATCH_REFCOUNT1(obj)
#endif
/* Object signals and args */
enum
{
@ -89,7 +111,7 @@ static void gst_object_dispatch_properties_changed (GObject * object,
static void gst_object_dispose (GObject * object);
static void gst_object_finalize (GObject * object);
static void gst_object_set_name_default (GstObject * object,
static gboolean gst_object_set_name_default (GstObject * object,
const gchar * type_name);
#ifndef GST_DISABLE_LOADSAVE_REGISTRY
@ -165,6 +187,7 @@ gst_object_class_init (GstObjectClass * klass)
G_TYPE_PARAM);
klass->path_string_separator = "/";
klass->lock = g_mutex_new ();
klass->signal_object = g_object_new (gst_signal_object_get_type (), NULL);
@ -187,10 +210,12 @@ gst_object_init (GTypeInstance * instance, gpointer g_class)
object->lock = g_mutex_new ();
object->parent = NULL;
object->name = NULL;
gst_atomic_int_init (&(object)->refcount, 1);
PATCH_REFCOUNT (object);
gst_object_set_name_default (object, G_OBJECT_CLASS_NAME (g_class));
object->flags = 0;
GST_FLAG_SET (object, GST_FLOATING);
GST_FLAG_SET (object, GST_OBJECT_FLOATING);
}
#ifndef GST_DISABLE_TRACE
@ -219,7 +244,13 @@ gst_object_constructor (GType type, guint n_construct_properties,
* gst_object_ref:
* @object: GstObject to reference
*
* Increments the refence count on the object.
* Increments the refence count on the object. This function
* does not take the lock on the object because it relies on
* atomic refcounting.
*
* This object returns the input parameter to ease writing
* constructs like :
* result = gst_object_ref (object->parent);
*
* Returns: A pointer to the object
*/
@ -228,10 +259,25 @@ gst_object_ref (GstObject * object)
{
g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
#ifdef DEBUG_REFCOUNT
#ifdef REFCOUNT_HACK
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "ref %d->%d",
G_OBJECT (object)->ref_count, G_OBJECT (object)->ref_count + 1);
GST_OBJECT_REFCOUNT_VALUE (object),
GST_OBJECT_REFCOUNT_VALUE (object) + 1);
#else
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "ref %d->%d",
((GObject *) object)->ref_count, ((GObject *) object)->ref_count + 1);
#endif
#endif
#ifdef REFCOUNT_HACK
gst_atomic_int_inc (&object->refcount);
PATCH_REFCOUNT (object);
#else
/* FIXME, not MT safe because glib is not MT safe */
g_object_ref (object);
#endif
g_object_ref (G_OBJECT (object));
return object;
}
@ -240,18 +286,53 @@ gst_object_ref (GstObject * object)
* @object: GstObject to unreference
*
* Decrements the refence count on the object. If reference count hits
* zero, destroy the object.
* zero, destroy the object. This function does not take the lock
* on the object as it relies on atomic refcounting.
*
* The unref method should never be called with the LOCK held since
* this might deadlock the dispose function.
*
* Returns: NULL, so that constructs like
*
* object = gst_object_unref (object);
*
* automatically clear the input object pointer.
*/
void
GstObject *
gst_object_unref (GstObject * object)
{
g_return_if_fail (GST_IS_OBJECT (object));
g_return_if_fail (G_OBJECT (object)->ref_count > 0);
g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
#ifdef REFCOUNT_HACK
g_return_val_if_fail (GST_OBJECT_REFCOUNT_VALUE (object) > 0, NULL);
#else
g_return_val_if_fail (((GObject *) object)->ref_count > 0, NULL);
#endif
#ifdef DEBUG_REFCOUNT
#ifdef REFCOUNT_HACK
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "unref %d->%d",
G_OBJECT (object)->ref_count, G_OBJECT (object)->ref_count - 1);
GST_OBJECT_REFCOUNT_VALUE (object),
GST_OBJECT_REFCOUNT_VALUE (object) - 1);
#else
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "unref %d->%d",
((GObject *) object)->ref_count, ((GObject *) object)->ref_count - 1);
#endif
#endif
g_object_unref (G_OBJECT (object));
#ifdef REFCOUNT_HACK
if (G_UNLIKELY (gst_atomic_int_dec_and_test (&object->refcount))) {
PATCH_REFCOUNT1 (object);
g_object_unref (object);
} else {
PATCH_REFCOUNT (object);
}
#else
/* FIXME, not MT safe because glib is not MT safe */
g_object_unref (object);
#endif
return NULL;
}
/**
@ -262,18 +343,25 @@ gst_object_unref (GstObject * object)
* a refcount of 1 and is FLOATING. This function should be used when
* creating a new object to symbolically 'take ownership' of the object.
* Use #gst_object_set_parent to have this done for you.
*
* This function takes the object lock.
*
* MT safe.
*/
void
gst_object_sink (GstObject * object)
{
g_return_if_fail (object != NULL);
g_return_if_fail (GST_IS_OBJECT (object));
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "sink");
if (GST_OBJECT_FLOATING (object)) {
GST_FLAG_UNSET (object, GST_FLOATING);
GST_LOCK (object);
if (G_LIKELY (GST_OBJECT_IS_FLOATING (object))) {
GST_FLAG_UNSET (object, GST_OBJECT_FLOATING);
GST_UNLOCK (object);
gst_object_unref (object);
} else {
GST_UNLOCK (object);
}
}
@ -283,7 +371,10 @@ gst_object_sink (GstObject * object)
* @newobj: new GstObject
*
* Unrefs the object pointer to by oldobj, refs the newobj and
* puts the newobj in *oldobj.
* puts the newobj in *oldobj. Be carefull when calling this
* function, it does not take any locks. You might want to lock
* the object owning the oldobj pointer before calling this
* function.
*/
void
gst_object_replace (GstObject ** oldobj, GstObject * newobj)
@ -292,13 +383,23 @@ gst_object_replace (GstObject ** oldobj, GstObject * newobj)
g_return_if_fail (*oldobj == NULL || GST_IS_OBJECT (*oldobj));
g_return_if_fail (newobj == NULL || GST_IS_OBJECT (newobj));
#ifdef DEBUG_REFCOUNT
#ifdef REFCOUNT_HACK
GST_CAT_LOG (GST_CAT_REFCOUNTING, "replace %s (%d) with %s (%d)",
*oldobj ? GST_STR_NULL (GST_OBJECT_NAME (*oldobj)) : "(NONE)",
*oldobj ? GST_OBJECT_REFCOUNT_VALUE (*oldobj) : 0,
newobj ? GST_STR_NULL (GST_OBJECT_NAME (newobj)) : "(NONE)",
newobj ? GST_OBJECT_REFCOUNT_VALUE (newobj) : 0);
#else
GST_CAT_LOG (GST_CAT_REFCOUNTING, "replace %s (%d) with %s (%d)",
*oldobj ? GST_STR_NULL (GST_OBJECT_NAME (*oldobj)) : "(NONE)",
*oldobj ? G_OBJECT (*oldobj)->ref_count : 0,
newobj ? GST_STR_NULL (GST_OBJECT_NAME (newobj)) : "(NONE)",
newobj ? G_OBJECT (newobj)->ref_count : 0);
#endif
#endif
if (*oldobj != newobj) {
if (G_LIKELY (*oldobj != newobj)) {
if (newobj)
gst_object_ref (newobj);
if (*oldobj)
@ -308,15 +409,22 @@ gst_object_replace (GstObject ** oldobj, GstObject * newobj)
}
}
/* dispose is called when the object has to release all links
* to other objects */
static void
gst_object_dispose (GObject * object)
{
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "dispose");
GST_FLAG_SET (GST_OBJECT (object), GST_DESTROYED);
GST_LOCK (object);
GST_FLAG_SET (GST_OBJECT (object), GST_OBJECT_DESTROYED);
GST_OBJECT_PARENT (object) = NULL;
GST_UNLOCK (object);
parent_class->dispose (object);
/* need to patch refcount so it is finalized */
PATCH_REFCOUNT1 (object)
parent_class->dispose (object);
}
/* finalize is called when the object has to free its resources */
@ -330,7 +438,6 @@ gst_object_finalize (GObject * object)
g_signal_handlers_destroy (object);
g_free (gstobject->name);
g_mutex_free (gstobject->lock);
#ifndef GST_DISABLE_TRACE
@ -352,34 +459,67 @@ gst_object_finalize (GObject * object)
* signals being emitted by the object itself, as well as in each parent
* object. This is so that an application can connect a listener to the
* top-level bin to catch property-change notifications for all contained
* elements. */
* elements.
*
* This function is not MT safe in glib so we need to lock it with a
* classwide mutex.
*
* MT safe.
*/
static void
gst_object_dispatch_properties_changed (GObject * object,
guint n_pspecs, GParamSpec ** pspecs)
{
GstObject *gst_object;
GstObject *gst_object, *parent, *old_parent;
guint i;
gchar *name, *debug_name;
GstObjectClass *klass;
/* we fail when this is not a GstObject */
g_return_if_fail (GST_IS_OBJECT (object));
klass = GST_OBJECT_GET_CLASS (object);
GST_CLASS_LOCK (klass);
/* do the standard dispatching */
PATCH_REFCOUNT (object);
G_OBJECT_CLASS (parent_class)->dispatch_properties_changed (object, n_pspecs,
pspecs);
PATCH_REFCOUNT (object);
gst_object = GST_OBJECT_CAST (object);
name = gst_object_get_name (gst_object);
debug_name = GST_STR_NULL (name);
/* now let the parent dispatch those, too */
gst_object = GST_OBJECT_PARENT (object);
while (gst_object) {
parent = gst_object_get_parent (gst_object);
while (parent) {
/* for debugging ... */
gchar *parent_name = gst_object_get_name (parent);
gchar *debug_parent_name = GST_STR_NULL (parent_name);
/* need own category? */
for (i = 0; i < n_pspecs; i++) {
GST_CAT_LOG (GST_CAT_SIGNAL, "deep notification from %s to %s (%s)",
GST_OBJECT_NAME (object) ? GST_OBJECT_NAME (object) : "(null)",
GST_OBJECT_NAME (gst_object) ? GST_OBJECT_NAME (gst_object) :
"(null)", pspecs[i]->name);
g_signal_emit (gst_object, gst_object_signals[DEEP_NOTIFY],
g_quark_from_string (pspecs[i]->name), (GstObject *) object,
pspecs[i]);
}
GST_CAT_LOG (GST_CAT_EVENT, "deep notification from %s to %s (%s)",
debug_name, debug_parent_name, pspecs[i]->name);
gst_object = GST_OBJECT_PARENT (gst_object);
/* not MT safe because of glib, fixed by taking class lock higher up */
PATCH_REFCOUNT (parent);
PATCH_REFCOUNT (object);
g_signal_emit (parent, gst_object_signals[DEEP_NOTIFY],
g_quark_from_string (pspecs[i]->name), GST_OBJECT_CAST (object),
pspecs[i]);
PATCH_REFCOUNT (parent);
PATCH_REFCOUNT (object);
}
g_free (parent_name);
old_parent = parent;
parent = gst_object_get_parent (old_parent);
gst_object_unref (old_parent);
}
g_free (name);
GST_CLASS_UNLOCK (klass);
}
/**
@ -395,6 +535,8 @@ gst_object_dispatch_properties_changed (GObject * object,
* strings that should be excluded from the notify.
* The default handler will print the new value of the property
* using g_print.
*
* MT safe.
*/
void
gst_object_default_deep_notify (GObject * object, GstObject * orig,
@ -438,11 +580,12 @@ gst_object_default_deep_notify (GObject * object, GstObject * orig,
}
}
static void
static gboolean
gst_object_set_name_default (GstObject * object, const gchar * type_name)
{
gint count;
gchar *name, *tmp;
gboolean result;
/* to ensure guaranteed uniqueness across threads, only one thread
* may ever assign a name */
@ -466,47 +609,133 @@ gst_object_set_name_default (GstObject * object, const gchar * type_name)
name = g_ascii_strdown (tmp, strlen (tmp));
g_free (tmp);
gst_object_set_name (object, name);
result = gst_object_set_name (object, name);
g_free (name);
return result;
}
/**
* gst_object_set_name:
* @object: GstObject to set the name of
* @name: new name of object
* @object: a #GstObject to set the name of
* @name: new name of object
*
* Sets the name of the object, or gives the element a guaranteed unique
* Sets the name of the object, or gives the object a guaranteed unique
* name (if @name is NULL).
* This function makes a copy of the provided name, so the caller
* retains ownership of the name it sent.
*
* Returns: TRUE if the name could be set. Objects that have
* a parent cannot be renamed.
*
* MT safe. This function grabs and releases the object's LOCK.
*/
void
gboolean
gst_object_set_name (GstObject * object, const gchar * name)
{
g_return_if_fail (object != NULL);
g_return_if_fail (GST_IS_OBJECT (object));
gboolean result;
if (object->name != NULL)
g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
GST_LOCK (object);
/* parented objects cannot be renamed */
if (G_UNLIKELY (object->parent != NULL))
goto had_parent;
if (name != NULL) {
g_free (object->name);
if (name != NULL)
object->name = g_strdup (name);
else
gst_object_set_name_default (object, G_OBJECT_TYPE_NAME (object));
GST_UNLOCK (object);
result = TRUE;
} else {
GST_UNLOCK (object);
result = gst_object_set_name_default (object, G_OBJECT_TYPE_NAME (object));
}
return result;
/* error */
had_parent:
{
GST_UNLOCK (object);
return FALSE;
}
}
/**
* gst_object_get_name:
* @object: GstObject to get the name of
* @object: a #GstObject to get the name of
*
* Get the name of the object.
* Returns a copy of the name of the object.
* Caller should g_free() the return value after usage.
* For a nameless object, this returns NULL, which you can safely g_free()
* as well.
*
* Returns: name of the object
* Returns: the name of the object. g_free() after usage.
*
* MT safe.
*/
const gchar *
gchar *
gst_object_get_name (GstObject * object)
{
gchar *result = NULL;
g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
return object->name;
GST_LOCK (object);
result = g_strdup (object->name);
GST_UNLOCK (object);
return result;
}
/**
* gst_object_set_name_prefix:
* @object: a #GstObject to set the name prefix of
* @name_prefix: new name prefix of object
*
* Sets the name prefix of the object.
* This function makes a copy of the provided name prefix, so the caller
* retains ownership of the name prefix it sent.
*
* MT safe. This function grabs and releases the object's LOCK.
*/
void
gst_object_set_name_prefix (GstObject * object, const gchar * name_prefix)
{
g_return_if_fail (GST_IS_OBJECT (object));
GST_LOCK (object);
g_free (object->name_prefix);
object->name_prefix = g_strdup (name_prefix); /* NULL gives NULL */
GST_UNLOCK (object);
}
/**
* gst_object_get_name_prefix:
* @object: a #GstObject to get the name prefix of
*
* Returns a copy of the name prefix of the object.
* Caller should g_free() the return value after usage.
* For a prefixless object, this returns NULL, which you can safely g_free()
* as well.
*
* Returns: the name prefix of the object. g_free() after usage.
*
* MT safe.
*/
gchar *
gst_object_get_name_prefix (GstObject * object)
{
gchar *result = NULL;
g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
GST_LOCK (object);
result = g_strdup (object->name_prefix);
GST_UNLOCK (object);
return result;
}
/**
@ -517,41 +746,78 @@ gst_object_get_name (GstObject * object)
* Sets the parent of @object. The object's reference count will be incremented,
* and any floating reference will be removed (see gst_object_sink()).
*
* This function takes the object lock.
*
* Causes the parent-set signal to be emitted.
*
* Returns: TRUE if the parent could be set or FALSE when the object
* already had a parent, the object and parent are the same or wrong
* parameters were provided.
*
* MT safe.
*/
void
gboolean
gst_object_set_parent (GstObject * object, GstObject * parent)
{
g_return_if_fail (object != NULL);
g_return_if_fail (GST_IS_OBJECT (object));
g_return_if_fail (parent != NULL);
g_return_if_fail (GST_IS_OBJECT (parent));
g_return_if_fail (object != parent);
g_return_if_fail (object->parent == NULL);
g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
g_return_val_if_fail (GST_IS_OBJECT (parent), FALSE);
g_return_val_if_fail (object != parent, FALSE);
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "set parent (ref and sink)");
gst_object_ref (object);
gst_object_sink (object);
GST_LOCK (object);
if (G_UNLIKELY (object->parent != NULL))
goto had_parent;
/* sink object, we don't call our own function because we don't
* need to release/acquire the lock needlessly or touch the refcount
* in the floating case. */
object->parent = parent;
if (G_LIKELY (GST_OBJECT_IS_FLOATING (object))) {
GST_FLAG_UNSET (object, GST_OBJECT_FLOATING);
GST_UNLOCK (object);
} else {
GST_UNLOCK (object);
gst_object_ref (object);
}
g_signal_emit (G_OBJECT (object), gst_object_signals[PARENT_SET], 0, parent);
return TRUE;
/* ERROR */
had_parent:
{
GST_UNLOCK (object);
return FALSE;
}
}
/**
* gst_object_get_parent:
* @object: GstObject to get parent of
*
* Returns the parent of @object.
* Returns the parent of @object. This function increases the refcount
* of the parent object so you should gst_object_unref() it after usage.
*
* Returns: parent of the object
* Returns: parent of the object, this can be NULL if the object has no
* parent. unref after usage.
*
* MT safe.
*/
GstObject *
gst_object_get_parent (GstObject * object)
{
g_return_val_if_fail (object != NULL, NULL);
GstObject *result = NULL;
g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
return object->parent;
GST_LOCK (object);
result = object->parent;
if (G_LIKELY (result))
gst_object_ref (result);
GST_UNLOCK (object);
return result;
}
/**
@ -559,22 +825,33 @@ gst_object_get_parent (GstObject * object)
* @object: GstObject to unparent
*
* Clear the parent of @object, removing the associated reference.
* This function decreases the refcount of the object so the object
* might not point to valid memory anymore after calling this function.
*
* MT safe.
*/
void
gst_object_unparent (GstObject * object)
{
g_return_if_fail (object != NULL);
GstObject *parent;
g_return_if_fail (GST_IS_OBJECT (object));
if (object->parent == NULL)
return;
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "unparent");
GST_LOCK (object);
parent = object->parent;
g_signal_emit (G_OBJECT (object), gst_object_signals[PARENT_UNSET], 0,
object->parent);
if (G_LIKELY (parent != NULL)) {
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "unparent");
object->parent = NULL;
GST_UNLOCK (object);
object->parent = NULL;
gst_object_unref (object);
g_signal_emit (G_OBJECT (object), gst_object_signals[PARENT_UNSET], 0,
parent);
gst_object_unref (object);
} else {
GST_UNLOCK (object);
}
}
/**
@ -582,25 +859,39 @@ gst_object_unparent (GstObject * object)
* @list: a list of #GstObject to check through
* @name: the name to search for
*
* Checks to see if there is any object named @name in @list.
* Checks to see if there is any object named @name in @list. This function
* does not do any locking of any kind. You might want to protect the
* provided list with the lock of the owner of the list. This function
* will lock each GstObject in the list to compare the name, so be
* carefull when passing a list with a locked object.
*
* Returns: TRUE if the name does not appear in the list, FALSE if it does.
*
* MT safe.
*/
gboolean
gst_object_check_uniqueness (GList * list, const gchar * name)
{
gboolean result = TRUE;
g_return_val_if_fail (name != NULL, FALSE);
while (list) {
GstObject *child = GST_OBJECT (list->data);
for (; list; list = g_list_next (list)) {
GstObject *child;
gboolean eq;
list = g_list_next (list);
child = GST_OBJECT (list->data);
if (strcmp (GST_OBJECT_NAME (child), name) == 0)
return FALSE;
GST_LOCK (child);
eq = strcmp (GST_OBJECT_NAME (child), name) == 0;
GST_UNLOCK (child);
if (G_UNLIKELY (eq)) {
result = FALSE;
break;
}
}
return TRUE;
return result;
}
@ -619,7 +910,6 @@ gst_object_save_thyself (GstObject * object, xmlNodePtr parent)
{
GstObjectClass *oclass;
g_return_val_if_fail (object != NULL, parent);
g_return_val_if_fail (GST_IS_OBJECT (object), parent);
g_return_val_if_fail (parent != NULL, parent);
@ -646,7 +936,6 @@ gst_object_restore_thyself (GstObject * object, xmlNodePtr self)
{
GstObjectClass *oclass;
g_return_if_fail (object != NULL);
g_return_if_fail (GST_IS_OBJECT (object));
g_return_if_fail (self != NULL);
@ -659,7 +948,6 @@ gst_object_restore_thyself (GstObject * object, xmlNodePtr self)
static void
gst_object_real_restore_thyself (GstObject * object, xmlNodePtr self)
{
g_return_if_fail (object != NULL);
g_return_if_fail (GST_IS_OBJECT (object));
g_return_if_fail (self != NULL);
@ -673,9 +961,6 @@ gst_object_set_property (GObject * object, guint prop_id,
{
GstObject *gstobject;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_OBJECT (object));
gstobject = GST_OBJECT (object);
switch (prop_id) {
@ -694,14 +979,11 @@ gst_object_get_property (GObject * object, guint prop_id,
{
GstObject *gstobject;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_OBJECT (object));
gstobject = GST_OBJECT (object);
switch (prop_id) {
case ARG_NAME:
g_value_set_string (value, (gchar *) GST_OBJECT_NAME (gstobject));
g_value_take_string (value, gst_object_get_name (gstobject));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -716,61 +998,63 @@ gst_object_get_property (GObject * object, guint prop_id,
* Generates a string describing the path of the object in
* the object hierarchy. Only useful (or used) for debugging.
*
* Returns: a string describing the path of the object
* Returns: a string describing the path of the object. You must
* g_free() the string after usage.
*
* MT safe.
*/
gchar *
gst_object_get_path_string (GstObject * object)
{
GSList *parentage = NULL;
GSList *parentage;
GSList *parents;
void *parent;
gchar *prevpath, *path;
const char *component;
gchar *separator = "";
gboolean free_component;
gchar *component;
gchar *separator;
/* ref object before adding to list */
gst_object_ref (object);
parentage = g_slist_prepend (NULL, object);
path = g_strdup ("");
/* first walk the object hierarchy to build a list of the parents */
/* first walk the object hierarchy to build a list of the parents,
* be carefull here with refcounting. */
do {
if (GST_IS_OBJECT (object)) {
parent = gst_object_get_parent (object);
/* add parents to list, refcount remains increased while
* we handle the object */
if (parent)
parentage = g_slist_prepend (parentage, parent);
} else {
parentage = g_slist_prepend (parentage, NULL);
parent = NULL;
break;
}
if (parent != NULL) {
parentage = g_slist_prepend (parentage, parent);
}
object = parent;
} while (object != NULL);
/* then walk the parent list and print them out */
parents = parentage;
while (parents) {
/* then walk the parent list and print them out. we need to
* decrease the refcounting on each element after we handled
* it. */
for (parents = parentage; parents; parents = g_slist_next (parents)) {
if (GST_IS_OBJECT (parents->data)) {
GstObjectClass *oclass = GST_OBJECT_GET_CLASS (parents->data);
GstObject *item = GST_OBJECT_CAST (parents->data);
GstObjectClass *oclass = GST_OBJECT_GET_CLASS (item);
component = gst_object_get_name (parents->data);
component = gst_object_get_name (item);
separator = oclass->path_string_separator;
free_component = FALSE;
/* and unref now */
gst_object_unref (item);
} else {
component = g_strdup_printf ("%p", parents->data);
separator = "/";
free_component = TRUE;
}
prevpath = path;
path = g_strjoin (separator, prevpath, component, NULL);
g_free (prevpath);
if (free_component)
g_free ((gchar *) component);
parents = g_slist_next (parents);
g_free (component);
}
g_slist_free (parentage);
@ -778,8 +1062,6 @@ gst_object_get_path_string (GstObject * object)
return path;
}
struct _GstSignalObject
{
GObject object;

View file

@ -1,6 +1,7 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* 2005 Wim Taymans <wim@fluendo.com>
*
* gstobject.h: Header for base GstObject
*
@ -28,6 +29,7 @@
#include <glib-object.h> /* note that this gets wrapped in __GST_OBJECT_H__ */
#include <gst/gstatomic.h>
#include <gst/gsttypes.h>
G_BEGIN_DECLS
@ -40,6 +42,8 @@ GST_EXPORT GType _gst_object_type;
#define GST_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_OBJECT, GstObjectClass))
#define GST_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_OBJECT, GstObject))
#define GST_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_OBJECT, GstObjectClass))
#define GST_OBJECT_CAST(obj) ((GstObject*)(obj))
#define GST_OBJECT_CLASS_CAST(klass) ((GstObjectClass*)(klass))
/* make sure we don't change the object size but stil make it compile
* without libxml */
@ -49,27 +53,57 @@ GST_EXPORT GType _gst_object_type;
typedef enum
{
GST_DESTROYED = 0,
GST_FLOATING,
GST_OBJECT_DISPOSING = 0,
GST_OBJECT_DESTROYED = 1,
GST_OBJECT_FLOATING,
GST_OBJECT_FLAG_LAST = 4
} GstObjectFlags;
#define GST_OBJECT_REFCOUNT(caps) ((GST_OBJECT_CAST(caps))->refcount)
#define GST_OBJECT_REFCOUNT_VALUE(caps) (gst_atomic_int_read (&(GST_OBJECT_CAST(caps))->refcount))
/* we do a GST_OBJECT_CAST to avoid type checking, better call these
* function with a valid object! */
#define GST_LOCK(obj) (g_mutex_lock(GST_OBJECT_CAST(obj)->lock))
#define GST_TRYLOCK(obj) (g_mutex_trylock(GST_OBJECT_CAST(obj)->lock))
#define GST_UNLOCK(obj) (g_mutex_unlock(GST_OBJECT_CAST(obj)->lock))
#define GST_GET_LOCK(obj) (GST_OBJECT_CAST(obj)->lock)
#define GST_OBJECT_NAME(obj) (GST_OBJECT_CAST(obj)->name)
#define GST_OBJECT_PARENT(obj) (GST_OBJECT_CAST(obj)->parent)
/* for the flags we double-not to make them comparable to TRUE and FALSE */
#define GST_FLAGS(obj) (GST_OBJECT_CAST (obj)->flags)
#define GST_FLAG_IS_SET(obj,flag) (!!(GST_FLAGS (obj) & (1<<(flag))))
#define GST_FLAG_SET(obj,flag) G_STMT_START{ (GST_FLAGS (obj) |= (1<<(flag))); }G_STMT_END
#define GST_FLAG_UNSET(obj,flag) G_STMT_START{ (GST_FLAGS (obj) &= ~(1<<(flag))); }G_STMT_END
#define GST_OBJECT_IS_DESTROYED(obj) (GST_FLAG_IS_SET (obj, GST_OBJECT_DESTROYED))
#define GST_OBJECT_IS_FLOATING(obj) (GST_FLAG_IS_SET (obj, GST_OBJECT_FLOATING))
struct _GstObject {
GObject object;
GObject object;
gchar *name;
/*< public >*/
GstAtomicInt refcount;
/* locking for all sorts of things */
GMutex *lock;
/* this object's parent */
GstObject *parent;
guint32 flags;
/*< public >*/ /* with LOCK */
GMutex *lock; /* object LOCK */
gchar *name; /* object name */
GstObject *parent; /* this object's parent, weak ref */
guint32 flags;
gchar *name_prefix; /* used for debugging */
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
#define GST_CLASS_LOCK(obj) (g_mutex_lock(GST_OBJECT_CLASS_CAST(obj)->lock))
#define GST_CLASS_TRYLOCK(obj) (g_mutex_trylock(GST_OBJECT_CLASS_CAST(obj)->lock))
#define GST_CLASS_UNLOCK(obj) (g_mutex_unlock(GST_OBJECT_CLASS_CAST(obj)->lock))
#define GST_CLASS_GET_LOCK(obj) (GST_OBJECT_CLASS_CAST(obj)->lock)
/* signal_object is used to signal to the whole class */
struct _GstObjectClass {
GObjectClass parent_class;
@ -77,57 +111,54 @@ struct _GstObjectClass {
gchar *path_string_separator;
GObject *signal_object;
GMutex *lock;
/* signals */
void (*parent_set) (GstObject *object, GstObject *parent);
void (*parent_unset) (GstObject *object, GstObject *parent);
void (*object_saved) (GstObject *object, xmlNodePtr parent);
void (*deep_notify) (GstObject *object, GstObject *orig, GParamSpec *pspec);
/* functions go here */
void (*destroy) (GstObject *object);
/* vtable */
xmlNodePtr (*save_thyself) (GstObject *object, xmlNodePtr parent);
void (*restore_thyself) (GstObject *object, xmlNodePtr self);
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
#define GST_FLAGS(obj) (GST_OBJECT (obj)->flags)
#define GST_FLAG_IS_SET(obj,flag) (GST_FLAGS (obj) & (1<<(flag)))
#define GST_FLAG_SET(obj,flag) G_STMT_START{ (GST_FLAGS (obj) |= (1<<(flag))); }G_STMT_END
#define GST_FLAG_UNSET(obj,flag) G_STMT_START{ (GST_FLAGS (obj) &= ~(1<<(flag))); }G_STMT_END
#define GST_OBJECT_NAME(obj) (const gchar*)(((GstObject *)(obj))->name)
#define GST_OBJECT_PARENT(obj) (((GstObject *)(obj))->parent)
#define GST_OBJECT_DESTROYED(obj) (GST_FLAG_IS_SET (obj, GST_DESTROYED))
#define GST_OBJECT_FLOATING(obj) (GST_FLAG_IS_SET (obj, GST_FLOATING))
/* CR1: object locking - GObject 2.0 doesn't have threadsafe locking */
#define GST_LOCK(obj) (g_mutex_lock(GST_OBJECT(obj)->lock))
#define GST_TRYLOCK(obj) (g_mutex_trylock(GST_OBJECT(obj)->lock))
#define GST_UNLOCK(obj) (g_mutex_unlock(GST_OBJECT(obj)->lock))
#define GST_GET_LOCK(obj) (GST_OBJECT(obj)->lock)
/* normal GObject stuff */
GType gst_object_get_type (void);
/* name routines */
void gst_object_set_name (GstObject *object, const gchar *name);
G_CONST_RETURN gchar*
gst_object_get_name (GstObject *object);
gboolean gst_object_set_name (GstObject *object, const gchar *name);
gchar* gst_object_get_name (GstObject *object);
void gst_object_set_name_prefix (GstObject *object, const gchar *name_prefix);
gchar* gst_object_get_name_prefix (GstObject *object);
/* parentage routines */
void gst_object_set_parent (GstObject *object, GstObject *parent);
gboolean gst_object_set_parent (GstObject *object, GstObject *parent);
GstObject* gst_object_get_parent (GstObject *object);
void gst_object_unparent (GstObject *object);
void gst_object_default_deep_notify (GObject *object, GstObject *orig,
GParamSpec *pspec, gchar **excluded_props);
/* refcounting + life cycle */
GstObject * gst_object_ref (GstObject *object);
GstObject * gst_object_unref (GstObject *object);
void gst_object_sink (GstObject *object);
/* replace object pointer */
void gst_object_replace (GstObject **oldobj, GstObject *newobj);
/* printing out the 'path' of the object */
gchar * gst_object_get_path_string (GstObject *object);
/* misc utils */
gboolean gst_object_check_uniqueness (GList *list, const gchar *name);
/* load/save */
#ifndef GST_DISABLE_LOADSAVE_REGISTRY
xmlNodePtr gst_object_save_thyself (GstObject *object, xmlNodePtr parent);
void gst_object_restore_thyself (GstObject *object, xmlNodePtr self);
@ -138,17 +169,7 @@ void gst_object_restore_thyself (GstObject *object, xmlNodePtr self);
#endif
#endif
/* refcounting + life cycle */
GstObject * gst_object_ref (GstObject *object);
void gst_object_unref (GstObject *object);
void gst_object_sink (GstObject *object);
/* replace object pointer */
void gst_object_replace (GstObject **oldobj, GstObject *newobj);
/* printing out the 'path' of the object */
gchar * gst_object_get_path_string (GstObject *object);
/* class signal stuff */
guint gst_class_signal_connect (GstObjectClass *klass,
const gchar *name,
gpointer func,

File diff suppressed because it is too large Load diff

View file

@ -50,8 +50,9 @@ GST_EXPORT GType _gst_ghost_pad_type;
#define GST_IS_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PAD))
#define GST_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PAD, GstPad))
#define GST_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PAD, GstPadClass))
#define GST_PAD_CAST(obj) ((GstPad*)(obj))
/*
/*
* Real Pads
*/
#define GST_TYPE_REAL_PAD (_gst_real_pad_type)
@ -60,6 +61,7 @@ GST_EXPORT GType _gst_ghost_pad_type;
#define GST_IS_REAL_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_REAL_PAD))
#define GST_REAL_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_REAL_PAD, GstRealPad))
#define GST_REAL_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_REAL_PAD, GstRealPadClass))
#define GST_REAL_PAD_CAST(obj) ((GstRealPad*)(obj))
/*
* Ghost Pads
@ -70,6 +72,7 @@ GST_EXPORT GType _gst_ghost_pad_type;
#define GST_IS_GHOST_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_GHOST_PAD))
#define GST_GHOST_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_GHOST_PAD, GstGhostPad))
#define GST_GHOST_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_GHOST_PAD, GstGhostPadClass))
#define GST_GHOST_PAD_CAST(obj) ((GstGhostPad*)(obj))
/*typedef struct _GstPad GstPad; */
@ -93,8 +96,24 @@ typedef enum {
#define GST_PAD_LINK_FAILED(ret) (ret < GST_PAD_LINK_OK)
#define GST_PAD_LINK_SUCCESSFUL(ret) (ret >= GST_PAD_LINK_OK)
typedef enum {
GST_FLOW_OK = 0, /* data passing was ok */
GST_FLOW_RESEND = 1, /* resend buffer, possibly with new caps */
GST_FLOW_ERROR = -1, /* some (fatal) error occured */
GST_FLOW_NOT_CONNECTED = -2, /* pad is not connected */
GST_FLOW_NOT_NEGOTIATED = -3, /* pad is not negotiated */
GST_FLOW_WRONG_STATE = -4, /* pad is in wrong state */
GST_FLOW_UNEXPECTED = -5, /* did not expect anything, this is not fatal */
GST_FLOW_NOT_SUPPORTED = -6 /* function not supported */
} GstFlowReturn;
typedef enum {
GST_ACTIVATE_NONE,
GST_ACTIVATE_PUSH,
GST_ACTIVATE_PULL,
} GstActivateMode;
/* convenience functions */
#ifndef GST_DISABLE_DEPRECATED
#ifdef G_HAVE_ISO_VARARGS
#define GST_PAD_QUERY_TYPE_FUNCTION(functionname, ...) GST_QUERY_TYPE_FUNCTION (GstPad *, functionname, __VA_ARGS__);
#define GST_PAD_FORMATS_FUNCTION(functionname, ...) GST_FORMATS_FUNCTION (GstPad *, functionname, __VA_ARGS__);
@ -104,8 +123,10 @@ typedef enum {
#define GST_PAD_FORMATS_FUNCTION(functionname, a...) GST_FORMATS_FUNCTION (GstPad *, functionname, a);
#define GST_PAD_EVENT_MASK_FUNCTION(functionname, a...) GST_EVENT_MASK_FUNCTION (GstPad *, functionname, a);
#endif
#endif
/* pad states */
typedef gboolean (*GstPadActivateFunction) (GstPad *pad, GstActivateMode mode);
/* this defines the functions used to chain buffers
* pad is the sink pad (so the same chain function can be used for N pads)
@ -138,7 +159,7 @@ typedef enum {
} GstPadDirection;
typedef enum {
GST_PAD_DISABLED = GST_OBJECT_FLAG_LAST,
GST_PAD_ACTIVE = GST_OBJECT_FLAG_LAST,
GST_PAD_NEGOTIATING,
GST_PAD_DISPATCHING,
@ -194,7 +215,9 @@ struct _GstRealPad {
GstPadEventFunction eventhandler;
GstPadEventMaskFunction eventmaskfunc;
GList *ghostpads;
/* ghostpads */
GList *ghostpads;
guint32 ghostpads_cookie;
/* query/convert/formats functions */
GstPadConvertFunction convertfunc;
@ -285,7 +308,7 @@ struct _GstGhostPadClass {
/* Some check functions (unused?) */
#define GST_PAD_IS_LINKED(pad) (GST_PAD_PEER(pad) != NULL)
#define GST_PAD_IS_ACTIVE(pad) (!GST_FLAG_IS_SET(GST_PAD_REALIZE(pad), GST_PAD_DISABLED))
#define GST_PAD_IS_ACTIVE(pad) (GST_FLAG_IS_SET(GST_PAD_REALIZE(pad), GST_PAD_ACTIVE))
#define GST_PAD_IS_NEGOTIATING(pad) (GST_FLAG_IS_SET (pad, GST_PAD_NEGOTIATING))
#define GST_PAD_IS_DISPATCHING(pad) (GST_FLAG_IS_SET (pad, GST_PAD_DISPATCHING))
#define GST_PAD_IS_USABLE(pad) (GST_PAD_IS_LINKED (pad) && \
@ -366,26 +389,23 @@ GstPad* gst_pad_new_from_template (GstPadTemplate *templ, const gchar *name);
GstPad* gst_pad_custom_new (GType type, const gchar *name, GstPadDirection direction);
GstPad* gst_pad_custom_new_from_template (GType type, GstPadTemplate *templ, const gchar *name);
void gst_pad_set_name (GstPad *pad, const gchar *name);
G_CONST_RETURN gchar* gst_pad_get_name (GstPad *pad);
#define gst_pad_get_name(pad) gst_object_get_name(GST_OBJECT(pad))
#define gst_pad_set_name(pad,name) gst_object_set_name(GST_OBJECT(pad),name)
#define gst_pad_get_parent(pad) GST_ELEMENT(gst_object_get_parent(GST_OBJECT(pad)))
#define gst_pad_set_parent(pad,parent) gst_object_set_parent(GST_OBJECT(pad),parent)
GstElement* gst_pad_get_real_parent (GstPad *pad);
GstPadDirection gst_pad_get_direction (GstPad *pad);
void gst_pad_set_active (GstPad *pad, gboolean active);
void gst_pad_set_active_recursive (GstPad *pad, gboolean active);
gboolean gst_pad_set_active (GstPad *pad, gboolean active);
gboolean gst_pad_is_active (GstPad *pad);
void gst_pad_set_element_private (GstPad *pad, gpointer priv);
gpointer gst_pad_get_element_private (GstPad *pad);
void gst_pad_set_parent (GstPad *pad, GstElement *parent);
GstElement* gst_pad_get_parent (GstPad *pad);
GstElement* gst_pad_get_real_parent (GstPad *pad);
GstScheduler* gst_pad_get_scheduler (GstPad *pad);
void gst_pad_add_ghost_pad (GstPad *pad, GstPad *ghostpad);
void gst_pad_remove_ghost_pad (GstPad *pad, GstPad *ghostpad);
GList* gst_pad_get_ghost_pad_list (GstPad *pad);
GstPadTemplate* gst_pad_get_pad_template (GstPad *pad);
@ -415,11 +435,13 @@ void gst_pad_unlink (GstPad *srcpad, GstPad *sinkpad);
gboolean gst_pad_is_linked (GstPad *pad);
GstPad* gst_pad_get_peer (GstPad *pad);
GstPad* gst_pad_realize (GstPad *pad);
/* capsnego functions */
G_CONST_RETURN GstCaps* gst_pad_get_negotiated_caps (GstPad *pad);
gboolean gst_pad_is_negotiated (GstPad *pad);
GstCaps* gst_pad_get_caps (GstPad *pad);
gboolean gst_pad_set_caps (GstPad *pad, GstCaps *caps);
G_CONST_RETURN GstCaps* gst_pad_get_pad_template_caps (GstPad *pad);
GstPadLinkReturn gst_pad_try_set_caps (GstPad *pad, const GstCaps *caps);
GstPadLinkReturn gst_pad_try_set_caps_nonfixed (GstPad *pad, const GstCaps *caps);
@ -428,17 +450,10 @@ gboolean gst_pad_check_compatibility (GstPad *srcpad, GstPad *sinkpad);
void gst_pad_set_getcaps_function (GstPad *pad, GstPadGetCapsFunction getcaps);
void gst_pad_set_fixate_function (GstPad *pad, GstPadFixateFunction fixate);
GstCaps * gst_pad_proxy_getcaps (GstPad *pad);
GstPadLinkReturn gst_pad_proxy_pad_link (GstPad *pad, const GstCaps *caps);
GstCaps * gst_pad_proxy_fixate (GstPad *pad, const GstCaps *caps);
#ifndef GST_DISABLE_DEPRECATED
GstPadLinkReturn gst_pad_proxy_link (GstPad *pad, const GstCaps *caps);
#endif
gboolean gst_pad_set_explicit_caps (GstPad *pad, const GstCaps *caps);
void gst_pad_use_explicit_caps (GstPad *pad);
gboolean gst_pad_relink_filtered (GstPad *srcpad, GstPad *sinkpad, const GstCaps *filtercaps);
#ifndef GST_DISABLE_DEPRECATED
gboolean gst_pad_perform_negotiate (GstPad *srcpad, GstPad *sinkpad);
#endif
GstPadLinkReturn gst_pad_renegotiate (GstPad *pad);
void gst_pad_unnegotiate (GstPad *pad);
gboolean gst_pad_try_relink_filtered (GstPad *srcpad, GstPad *sinkpad, const GstCaps *filtercaps);
@ -447,16 +462,14 @@ void gst_pad_caps_change_notify (GstPad *pad);
gboolean gst_pad_recover_caps_error (GstPad *pad, const GstCaps *allowed);
GstCaps * gst_pad_peer_get_caps (GstPad * pad);
/* data passing functions */
void gst_pad_push (GstPad *pad, GstData *data);
GstData* gst_pad_pull (GstPad *pad);
gboolean gst_pad_send_event (GstPad *pad, GstEvent *event);
gboolean gst_pad_event_default (GstPad *pad, GstEvent *event);
#ifndef GST_DISABLE_DEPRECATED
GstPad* gst_pad_selectv (GList *padlist);
GstPad* gst_pad_select (GstPad *pad, ...);
GstPad* gst_pad_select_valist (GstPad *pad, va_list varargs);
#endif
/* FIXME 0.9: rename to _select? Otherwise rename SchedulerClass pointer */
GstData * gst_pad_collectv (GstPad **selected, const GList *padlist);
GstData * gst_pad_collect (GstPad **selected, GstPad *pad, ...);
@ -497,6 +510,7 @@ GList* gst_pad_get_internal_links_default (GstPad *pad);
gboolean gst_pad_dispatcher (GstPad *pad, GstPadDispatcherFunction dispatch,
gpointer data);
/* probes */
#define gst_pad_add_probe(pad, probe) \
(gst_probe_dispatcher_add_probe (&(GST_PAD_REALIZE (pad)->probedisp), probe))
#define gst_pad_remove_probe(pad, probe) \
@ -520,9 +534,6 @@ GstPadTemplate* gst_pad_template_new (const gchar *name_template,
GstPadTemplate * gst_static_pad_template_get (GstStaticPadTemplate *pad_template);
const GstCaps* gst_pad_template_get_caps (GstPadTemplate *templ);
#ifndef GST_DISABLE_DEPRECATED
const GstCaps* gst_pad_template_get_caps_by_name (GstPadTemplate *templ, const gchar *name);
#endif
#ifndef GST_DISABLE_LOADSAVE
xmlNodePtr gst_ghost_pad_save_thyself (GstPad *pad,

View file

@ -1,6 +1,6 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* 2004,2005 Wim Taymans <wim@fluendo.com>
*
* gstpipeline.c: Overall pipeline management element
*
@ -30,7 +30,7 @@ static GstElementDetails gst_pipeline_details =
GST_ELEMENT_DETAILS ("Pipeline object",
"Generic/Bin",
"Complete pipeline object",
"Erik Walthinsen <omega@cse.ogi.edu>");
"Erik Walthinsen <omega@cse.ogi.edu>, Wim Taymans <wim@fluendo.com>");
/* Pipeline signals and args */
enum
@ -39,6 +39,8 @@ enum
LAST_SIGNAL
};
#define DEFAULT_DELAY 0
#define DEFAULT_PLAY_TIMEOUT (2*GST_SECOND)
enum
{
ARG_0
@ -134,8 +136,8 @@ gst_pipeline_dispose (GObject * object)
GstPipeline *pipeline = GST_PIPELINE (object);
GstScheduler *sched;
g_assert (GST_IS_SCHEDULER (GST_ELEMENT_SCHED (pipeline)));
sched = GST_ELEMENT_SCHED (pipeline);
g_assert (GST_IS_SCHEDULER (GST_ELEMENT_SCHEDULER (pipeline)));
sched = GST_ELEMENT_SCHEDULER (pipeline);
gst_scheduler_reset (sched);
G_OBJECT_CLASS (parent_class)->dispose (object);
@ -148,6 +150,8 @@ gst_pipeline_dispose (GObject * object)
* Create a new pipeline with the given name.
*
* Returns: newly created GstPipeline
*
* MT safe.
*/
GstElement *
gst_pipeline_new (const gchar * name)
@ -160,7 +164,7 @@ gst_pipeline_change_state (GstElement * element)
{
switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_NULL_TO_READY:
gst_scheduler_setup (GST_ELEMENT_SCHED (element));
gst_scheduler_setup (GST_ELEMENT_SCHEDULER (element));
break;
case GST_STATE_READY_TO_PAUSED:
case GST_STATE_PAUSED_TO_PLAYING:

View file

@ -24,6 +24,7 @@
#ifndef __GST_PIPELINE_H__
#define __GST_PIPELINE_H__
#include <gst/gsttypes.h>
#include <gst/gstbin.h>
G_BEGIN_DECLS
@ -35,18 +36,33 @@ G_BEGIN_DECLS
#define GST_IS_PIPELINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PIPELINE))
#define GST_PIPELINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_PIPELINE, GstPipelineClass))
typedef struct _GstPipeline GstPipeline;
typedef struct _GstPipelineClass GstPipelineClass;
typedef enum {
/* this pipeline works with a fixed clock */
GST_PIPELINE_FLAG_FIXED_CLOCK = GST_BIN_FLAG_LAST,
/* padding */
GST_PIPELINE_FLAG_LAST = GST_BIN_FLAG_LAST + 4
} GstPipelineFlags;
struct _GstPipeline {
GstBin bin;
/*< public >*/ /* with LOCK */
GstClock *fixed_clock; /* fixed clock if any */
GstClockTime stream_time;
GstClockTime delay;
GstClockTime play_timeout;
GList *eosed; /* list of elements that posted EOS */
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
struct _GstPipelineClass {
GstBinClass parent_class;
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
@ -54,6 +70,11 @@ GType gst_pipeline_get_type (void);
GstElement* gst_pipeline_new (const gchar *name);
void gst_pipeline_use_clock (GstPipeline *pipeline, GstClock *clock);
void gst_pipeline_set_clock (GstPipeline *pipeline, GstClock *clock);
GstClock* gst_pipeline_get_clock (GstPipeline *pipeline);
void gst_pipeline_auto_clock (GstPipeline *pipeline);
G_END_DECLS
#endif /* __GST_PIPELINE_H__ */

View file

@ -114,7 +114,7 @@ gst_plugin_error_quark (void)
* plugin description in a list to initialize it when we open the main
* module later on.
* When the main module is known, we can register the plugin right away.
* */
*/
void
_gst_plugin_register_static (GstPluginDesc * desc)
{

View file

@ -154,23 +154,6 @@ gst_plugin_feature_type_name_filter (GstPluginFeature * feature,
|| !strcmp (data->name, GST_PLUGIN_FEATURE_NAME (feature))));
}
/**
* gst_plugin_feature_set_rank:
* @feature: feature to rank
* @rank: rank value - higher number means more priority rank
*
* Specifies a rank for a plugin feature, so that autoplugging uses
* the most appropriate feature.
*/
void
gst_plugin_feature_set_rank (GstPluginFeature * feature, guint rank)
{
g_return_if_fail (feature != NULL);
g_return_if_fail (GST_IS_PLUGIN_FEATURE (feature));
feature->rank = rank;
}
/**
* gst_plugin_feature_set_name:
* @feature: a feature
@ -178,7 +161,8 @@ gst_plugin_feature_set_rank (GstPluginFeature * feature, guint rank)
*
* Sets the name of a plugin feature. The name uniquely identifies a feature
* within all features of the same type. Renaming a plugin feature is not
* allowed.
* allowed. A copy is made of the name so you should free the supplied @name
* after calling this function.
*/
void
gst_plugin_feature_set_name (GstPluginFeature * feature, const gchar * name)
@ -193,22 +177,6 @@ gst_plugin_feature_set_name (GstPluginFeature * feature, const gchar * name)
}
}
/**
* gst_plugin_feature_get rank:
* @feature: a feature
*
* Gets the rank of a plugin feature.
*
* Returns: The rank of the feature
*/
guint
gst_plugin_feature_get_rank (GstPluginFeature * feature)
{
g_return_val_if_fail (GST_IS_PLUGIN_FEATURE (feature), GST_RANK_NONE);
return feature->rank;
}
/**
* gst_plugin_feature_get_name:
* @feature: a feature
@ -224,3 +192,36 @@ gst_plugin_feature_get_name (GstPluginFeature * feature)
return feature->name;
}
/**
* gst_plugin_feature_set_rank:
* @feature: feature to rank
* @rank: rank value - higher number means more priority rank
*
* Specifies a rank for a plugin feature, so that autoplugging uses
* the most appropriate feature.
*/
void
gst_plugin_feature_set_rank (GstPluginFeature * feature, guint rank)
{
g_return_if_fail (feature != NULL);
g_return_if_fail (GST_IS_PLUGIN_FEATURE (feature));
feature->rank = rank;
}
/**
* gst_plugin_feature_get rank:
* @feature: a feature
*
* Gets the rank of a plugin feature.
*
* Returns: The rank of the feature
*/
guint
gst_plugin_feature_get_rank (GstPluginFeature * feature)
{
g_return_val_if_fail (GST_IS_PLUGIN_FEATURE (feature), GST_RANK_NONE);
return feature->rank;
}

View file

@ -58,6 +58,7 @@ struct _GstPluginFeatureClass {
void (*unload_thyself) (GstPluginFeature *feature);
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};

View file

@ -49,7 +49,9 @@ gst_probe_get_type (void)
* @callback: the function to call when the probe is triggered
* @user_data: data passed to the callback function
*
* Create a new probe with the specified parameters
* Create a new probe with the specified parameters. The single shot
* probe will be fired only once. It is the responsability of the
* application to free the single probe after it has been fired.
*
* Returns: a new #GstProbe.
*/
@ -255,7 +257,8 @@ gst_probe_dispatcher_dispatch (GstProbeDispatcher * disp, GstData ** data)
g_slist_find (disp->probes, probe) && probe->single_shot) {
disp->probes = g_slist_remove (disp->probes, probe);
gst_probe_destroy (probe);
/* do not free the probe here as it cannot be made threadsafe */
//gst_probe_destroy (probe);
}
}

View file

@ -1,6 +1,7 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wim.taymans@chello.be>
* 2005 Wim Taymans <wim@fluendo.com>
*
* gstquery.c: GstQueryType registration
*
@ -25,10 +26,11 @@
#include "gst_private.h"
#include "gstquery.h"
static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
static GList *_gst_queries = NULL;
static GHashTable *_nick_to_query = NULL;
static GHashTable *_query_type_to_nick = NULL;
static gint _n_values = 1; /* we start from 1 because 0 reserved for NONE */
static guint32 _n_values = 1; /* we start from 1 because 0 reserved for NONE */
static GstQueryTypeDefinition standard_definitions[] = {
{GST_QUERY_TOTAL, "total", "Total length"},
@ -46,6 +48,7 @@ _gst_query_type_initialize (void)
{
GstQueryTypeDefinition *standards = standard_definitions;
g_static_mutex_lock (&mutex);
if (_nick_to_query == NULL) {
_nick_to_query = g_hash_table_new (g_str_hash, g_str_equal);
_query_type_to_nick = g_hash_table_new (NULL, NULL);
@ -60,6 +63,7 @@ _gst_query_type_initialize (void)
standards++;
_n_values++;
}
g_static_mutex_unlock (&mutex);
}
/**
@ -91,11 +95,13 @@ gst_query_type_register (const gchar * nick, const gchar * description)
query->nick = g_strdup (nick);
query->description = g_strdup (description);
g_static_mutex_lock (&mutex);
g_hash_table_insert (_nick_to_query, query->nick, query);
g_hash_table_insert (_query_type_to_nick, GINT_TO_POINTER (query->value),
query);
_gst_queries = g_list_append (_gst_queries, query);
_n_values++;
g_static_mutex_unlock (&mutex);
return query->value;
}
@ -116,7 +122,9 @@ gst_query_type_get_by_nick (const gchar * nick)
g_return_val_if_fail (nick != NULL, 0);
g_static_mutex_lock (&mutex);
query = g_hash_table_lookup (_nick_to_query, nick);
g_static_mutex_unlock (&mutex);
if (query != NULL)
return query->value;
@ -160,18 +168,32 @@ gst_query_types_contains (const GstQueryType * types, GstQueryType type)
const GstQueryTypeDefinition *
gst_query_type_get_details (GstQueryType type)
{
return g_hash_table_lookup (_query_type_to_nick, GINT_TO_POINTER (type));
const GstQueryTypeDefinition *result;
g_static_mutex_lock (&mutex);
result = g_hash_table_lookup (_query_type_to_nick, GINT_TO_POINTER (type));
g_static_mutex_unlock (&mutex);
return result;
}
/**
* gst_query_type_get_definitions:
* gst_query_type_iterate_definitions:
*
* Get a list of all the registered query types.
* Get an Iterator of all the registered query types. The querytype
* definition is read only.
*
* Returns: A GList of #GstQueryTypeDefinition.
* Returns: A #GstIterator of #GstQueryTypeDefinition.
*/
const GList *
gst_query_type_get_definitions (void)
GstIterator *
gst_query_type_iterate_definitions (void)
{
return _gst_queries;
GstIterator *result;
g_static_mutex_lock (&mutex);
result = gst_iterator_new_list (g_static_mutex_get_mutex (&mutex),
&_n_values, &_gst_queries, NULL, NULL, NULL);
g_static_mutex_unlock (&mutex);
return result;
}

View file

@ -1,6 +1,7 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wim.taymans@chello.be>
* 2005 Wim Taymans <wim@fluendo.com>
*
* gstquery.h: GstQuery API declaration
*
@ -26,6 +27,8 @@
#include <glib.h>
#include <gst/gstiterator.h>
G_BEGIN_DECLS
typedef enum {
@ -87,8 +90,8 @@ gboolean gst_query_types_contains (const GstQueryType *types, GstQ
/* query for query details */
G_CONST_RETURN GstQueryTypeDefinition*
gst_query_type_get_details (GstQueryType type);
G_CONST_RETURN GList* gst_query_type_get_definitions (void);
gst_query_type_get_details (GstQueryType type);
GstIterator* gst_query_type_iterate_definitions (void);
G_END_DECLS

View file

@ -434,6 +434,8 @@ gst_queue_link_sink (GstPad * pad, const GstCaps * caps)
GST_QUEUE_MUTEX_UNLOCK;
}
link_ret = GST_PAD_LINK_OK;
#if 0
link_ret = gst_pad_proxy_pad_link (pad, caps);
if (GST_PAD_LINK_SUCCESSFUL (link_ret)) {
@ -441,6 +443,7 @@ gst_queue_link_sink (GstPad * pad, const GstCaps * caps)
* the pads become unnegotiated while we have buffers */
gst_caps_replace (&queue->negotiated_caps, gst_caps_copy (caps));
}
#endif
return link_ret;
}
@ -459,8 +462,10 @@ gst_queue_link_src (GstPad * pad, const GstCaps * caps)
}
return GST_PAD_LINK_REFUSED;
}
#if 0
link_ret = gst_pad_proxy_pad_link (pad, caps);
#endif
link_ret = GST_PAD_LINK_OK;
if (GST_PAD_LINK_SUCCESSFUL (link_ret)) {
/* we store an extra copy of the negotiated caps, just in case

View file

@ -227,14 +227,14 @@ gst_scheduler_add_element (GstScheduler * sched, GstElement * element)
g_return_if_fail (GST_IS_ELEMENT (element));
/* if it's already in this scheduler, don't bother doing anything */
if (GST_ELEMENT_SCHED (element) == sched) {
if (GST_ELEMENT_SCHEDULER (element) == sched) {
GST_CAT_DEBUG (GST_CAT_SCHEDULING, "element %s already in scheduler %p",
GST_ELEMENT_NAME (element), sched);
return;
}
/* if it's not inside this scheduler, it has to be NULL */
g_assert (GST_ELEMENT_SCHED (element) == NULL);
g_assert (GST_ELEMENT_SCHEDULER (element) == NULL);
if (gst_element_provides_clock (element)) {
sched->clock_providers = g_list_prepend (sched->clock_providers, element);
@ -970,7 +970,7 @@ gst_scheduler_factory_create (GstSchedulerFactory * factory,
sched = GST_SCHEDULER (g_object_new (factory->type, NULL));
sched->parent = parent;
GST_ELEMENT_SCHED (parent) = sched;
GST_ELEMENT_SCHEDULER (parent) = sched;
/* let's refcount the scheduler */
gst_object_ref (GST_OBJECT (sched));

View file

@ -40,6 +40,10 @@ struct _GstStructureField
#define GST_STRUCTURE_FIELD(structure, index) \
&g_array_index((structure)->fields, GstStructureField, (index))
#define IS_MUTABLE(structure) \
(!(structure)->parent_refcount || \
gst_atomic_int_read ((structure)->parent_refcount) == 1)
static void gst_structure_set_field (GstStructure * structure,
GstStructureField * field);
static GstStructureField *gst_structure_get_field (const GstStructure *
@ -173,6 +177,30 @@ gst_structure_new_valist (const gchar * name,
return structure;
}
/**
* gst_structure_set_parent_refcount:
* @structure: a #GstStructure
* @refcount: a pointer to the parent's #GstAtomicInt refcount
*
* Sets the parent_refcount field of #GstStructure. This field is used to
* determine whether a structure is mutable or not. This function should only be
* called by code implementing parent objects of GstStructure, as described in
* the MT Refcounting section of the design documents.
*
* Returns: a new #GstStructure.
*/
void
gst_structure_set_parent_refcount (GstStructure * structure,
GstAtomicInt * refcount)
{
if (structure->parent_refcount)
g_return_if_fail (refcount == NULL);
else
g_return_if_fail (refcount != NULL);
structure->parent_refcount = refcount;
}
/**
* gst_structure_copy:
* @structure: a #GstStructure to duplicate
@ -211,7 +239,8 @@ gst_structure_copy (const GstStructure * structure)
* gst_structure_free:
* @structure: the #GstStructure to free
*
* Frees a #GstStructure and all its fields and values.
* Frees a #GstStructure and all its fields and values. The structure must not
* parent when this function is called.
*/
void
gst_structure_free (GstStructure * structure)
@ -220,6 +249,7 @@ gst_structure_free (GstStructure * structure)
int i;
g_return_if_fail (structure != NULL);
g_return_if_fail (structure->parent_refcount == NULL);
for (i = 0; i < structure->fields->len; i++) {
field = GST_STRUCTURE_FIELD (structure, i);
@ -280,6 +310,7 @@ gst_structure_set_name (GstStructure * structure, const gchar * name)
{
g_return_if_fail (structure != NULL);
g_return_if_fail (name != NULL);
g_return_if_fail (IS_MUTABLE (structure));
structure->name = g_quark_from_string (name);
}
@ -302,6 +333,7 @@ gst_structure_id_set_value (GstStructure * structure,
g_return_if_fail (structure != NULL);
g_return_if_fail (G_IS_VALUE (value));
g_return_if_fail (IS_MUTABLE (structure));
gsfield.name = field;
gst_value_init_and_copy (&gsfield.value, value);
@ -326,6 +358,7 @@ gst_structure_set_value (GstStructure * structure,
g_return_if_fail (structure != NULL);
g_return_if_fail (fieldname != NULL);
g_return_if_fail (G_IS_VALUE (value));
g_return_if_fail (IS_MUTABLE (structure));
gst_structure_id_set_value (structure, g_quark_from_string (fieldname),
value);
@ -373,6 +406,7 @@ gst_structure_set_valist (GstStructure * structure,
char *s;
g_return_if_fail (structure != NULL);
g_return_if_fail (IS_MUTABLE (structure));
while (fieldname) {
GstStructureField field = { 0 };
@ -451,18 +485,9 @@ gst_structure_set_valist (GstStructure * structure,
}
}
/**
* gst_structure_set_field:
* @structure: a #GstStructure
* @field: the #GstStructureField to set
*
* Sets a field in the structure. If the structure currently contains
* a field with the same name, it is replaced with the provided field.
* Otherwise, the field is added to the structure. The field's value
* is not deeply copied.
*
* This function is intended mainly for internal use. The function
* #gst_structure_set() is recommended instead of this one.
/* If the structure currently contains a field with the same name, it is
* replaced with the provided field. Otherwise, the field is added to the
* structure. The field's value is not deeply copied.
*/
static void
gst_structure_set_field (GstStructure * structure, GstStructureField * field)
@ -483,15 +508,7 @@ gst_structure_set_field (GstStructure * structure, GstStructureField * field)
g_array_append_val (structure->fields, *field);
}
/* FIXME: is this private ? if so remove gtk-doc
* gst_structure_id_get_field:
* @structure: a #GstStructure
* @field_id: the GQuark of the field to get
*
* Gets the specified field from the structure. If there is no
* field with the given ID, NULL is returned.
*
* Returns: the #GstStructureField with the given ID
/* If there is no field with the given ID, NULL is returned.
*/
static GstStructureField *
gst_structure_id_get_field (const GstStructure * structure, GQuark field_id)
@ -511,15 +528,7 @@ gst_structure_id_get_field (const GstStructure * structure, GQuark field_id)
return NULL;
}
/**
* gst_structure_get_field:
* @structure: a #GstStructure
* @fieldname: the name of the field to get
*
* Gets the specified field from the structure. If there is no
* field with the given ID, NULL is returned.
*
* Returns: the #GstStructureField with the given name
/* If there is no field with the given ID, NULL is returned.
*/
static GstStructureField *
gst_structure_get_field (const GstStructure * structure,
@ -598,6 +607,7 @@ gst_structure_remove_field (GstStructure * structure, const gchar * fieldname)
g_return_if_fail (structure != NULL);
g_return_if_fail (fieldname != NULL);
g_return_if_fail (IS_MUTABLE (structure));
id = g_quark_from_string (fieldname);
@ -631,6 +641,7 @@ gst_structure_remove_fields (GstStructure * structure,
g_return_if_fail (structure != NULL);
g_return_if_fail (fieldname != NULL);
/* mutability checked in remove_field */
va_start (varargs, fieldname);
@ -656,6 +667,7 @@ gst_structure_remove_fields_valist (GstStructure * structure,
g_return_if_fail (structure != NULL);
g_return_if_fail (fieldname != NULL);
/* mutability checked in remove_field */
while (field) {
gst_structure_remove_field (structure, field);
@ -676,6 +688,7 @@ gst_structure_remove_all_fields (GstStructure * structure)
int i;
g_return_if_fail (structure != NULL);
g_return_if_fail (IS_MUTABLE (structure));
for (i = structure->fields->len - 1; i >= 0; i--) {
field = GST_STRUCTURE_FIELD (structure, i);
@ -736,19 +749,57 @@ gst_structure_n_fields (const GstStructure * structure)
* @func: a function to call for each field
* @user_data: private data
*
* Calls the provided function once for each field in the #GstStructure.
* Calls the provided function once for each field in the #GstStructure. The
* function must not modify the fields. Also see gst_structure_map_in_place().
*
* Returns: TRUE if the supplied function returns TRUE For each of the fields,
* FALSE otherwise.
*/
gboolean
gst_structure_foreach (GstStructure * structure,
gst_structure_foreach (const GstStructure * structure,
GstStructureForeachFunc func, gpointer user_data)
{
int i;
GstStructureField *field;
gboolean ret;
g_return_val_if_fail (structure != NULL, FALSE);
for (i = 0; i < structure->fields->len; i++) {
field = GST_STRUCTURE_FIELD (structure, i);
ret = func (field->name, &field->value, user_data);
if (!ret)
return FALSE;
}
return TRUE;
}
/**
* gst_structure_map_in_place:
* @structure: a #GstStructure
* @func: a function to call for each field
* @user_data: private data
*
* Calls the provided function once for each field in the #GstStructure. In
* contrast to gst_structure_foreach(), the function may modify the fields. The
* structure must be mutable.
*
* Returns: TRUE if the supplied function returns TRUE For each of the fields,
* FALSE otherwise.
*/
gboolean
gst_structure_map_in_place (GstStructure * structure,
GstStructureMapFunc func, gpointer user_data)
{
int i;
GstStructureField *field;
gboolean ret;
g_return_val_if_fail (structure != NULL, FALSE);
g_return_val_if_fail (IS_MUTABLE (structure), FALSE);
for (i = 0; i < structure->fields->len; i++) {
field = GST_STRUCTURE_FIELD (structure, i);
@ -1548,3 +1599,134 @@ gst_structure_copy_conditional (const GstStructure * structure)
return gst_structure_copy (structure);
return NULL;
}
/* fixate utility functions */
/**
* gst_caps_structure_fixate_field_nearest_int:
* @structure: a #GstStructure
* @field_name: a field in @structure
* @target: the target value of the fixation
*
* Fixates a #GstStructure by changing the given field to the nearest
* integer to @target that is a subset of the existing field.
*
* Returns: TRUE if the structure could be fixated
*/
gboolean
gst_caps_structure_fixate_field_nearest_int (GstStructure * structure,
const char *field_name, int target)
{
const GValue *value;
g_return_val_if_fail (gst_structure_has_field (structure, field_name), FALSE);
g_return_val_if_fail (IS_MUTABLE (structure), FALSE);
value = gst_structure_get_value (structure, field_name);
if (G_VALUE_TYPE (value) == G_TYPE_INT) {
/* already fixed */
return FALSE;
} else if (G_VALUE_TYPE (value) == GST_TYPE_INT_RANGE) {
int x;
x = gst_value_get_int_range_min (value);
if (target < x)
target = x;
x = gst_value_get_int_range_max (value);
if (target > x)
target = x;
gst_structure_set (structure, field_name, G_TYPE_INT, target, NULL);
return TRUE;
} else if (G_VALUE_TYPE (value) == GST_TYPE_LIST) {
const GValue *list_value;
int i, n;
int best = 0;
int best_index = -1;
n = gst_value_list_get_size (value);
for (i = 0; i < n; i++) {
list_value = gst_value_list_get_value (value, i);
if (G_VALUE_TYPE (list_value) == G_TYPE_INT) {
int x = g_value_get_int (list_value);
if (best_index == -1 || (ABS (target - x) < ABS (target - best))) {
best_index = i;
best = x;
}
}
}
if (best_index != -1) {
gst_structure_set (structure, field_name, G_TYPE_INT, best, NULL);
return TRUE;
}
return FALSE;
}
return FALSE;
}
/**
* gst_caps_structure_fixate_field_nearest_double:
* @structure: a #GstStructure
* @field_name: a field in @structure
* @target: the target value of the fixation
*
* Fixates a #GstStructure by changing the given field to the nearest
* double to @target that is a subset of the existing field.
*
* Returns: TRUE if the structure could be fixated
*/
gboolean
gst_caps_structure_fixate_field_nearest_double (GstStructure * structure,
const char *field_name, double target)
{
const GValue *value;
g_return_val_if_fail (gst_structure_has_field (structure, field_name), FALSE);
g_return_val_if_fail (IS_MUTABLE (structure), FALSE);
value = gst_structure_get_value (structure, field_name);
if (G_VALUE_TYPE (value) == G_TYPE_DOUBLE) {
/* already fixed */
return FALSE;
} else if (G_VALUE_TYPE (value) == GST_TYPE_DOUBLE_RANGE) {
double x;
x = gst_value_get_double_range_min (value);
if (target < x)
target = x;
x = gst_value_get_double_range_max (value);
if (target > x)
target = x;
gst_structure_set (structure, field_name, G_TYPE_DOUBLE, target, NULL);
return TRUE;
} else if (G_VALUE_TYPE (value) == GST_TYPE_LIST) {
const GValue *list_value;
int i, n;
double best = 0;
int best_index = -1;
n = gst_value_list_get_size (value);
for (i = 0; i < n; i++) {
list_value = gst_value_list_get_value (value, i);
if (G_VALUE_TYPE (list_value) == G_TYPE_DOUBLE) {
double x = g_value_get_double (list_value);
if (best_index == -1 || (ABS (target - x) < ABS (target - best))) {
best_index = i;
best = x;
}
}
}
if (best_index != -1) {
gst_structure_set (structure, field_name, G_TYPE_DOUBLE, best, NULL);
return TRUE;
}
return FALSE;
}
return FALSE;
}

View file

@ -33,14 +33,22 @@ G_BEGIN_DECLS
typedef struct _GstStructure GstStructure;
typedef gboolean (*GstStructureForeachFunc) (GQuark field_id,
const GValue * value,
gpointer user_data);
typedef gboolean (*GstStructureMapFunc) (GQuark field_id,
GValue * value,
gpointer user_data);
struct _GstStructure {
GType type;
/*< private >*/
GQuark name;
/* owned by parent structure, NULL if no parent */
GstAtomicInt *parent_refcount;
GArray *fields;
gpointer _gst_reserved[GST_PADDING];
@ -57,6 +65,8 @@ GstStructure * gst_structure_new_valist (const gchar *
const gchar * firstfield,
va_list varargs);
GstStructure * gst_structure_copy (const GstStructure *structure);
void gst_structure_set_parent_refcount (GstStructure *structure,
GstAtomicInt *refcount);
void gst_structure_free (GstStructure *structure);
G_CONST_RETURN gchar * gst_structure_get_name (const GstStructure *structure);
@ -92,9 +102,12 @@ void gst_structure_remove_all_fields (GstStructure
GType gst_structure_get_field_type (const GstStructure *structure,
const gchar *fieldname);
gboolean gst_structure_foreach (GstStructure *structure,
gboolean gst_structure_foreach (const GstStructure *structure,
GstStructureForeachFunc func,
gpointer user_data);
gboolean gst_structure_map_in_place (GstStructure *structure,
GstStructureMapFunc func,
gpointer user_data);
gint gst_structure_n_fields (const GstStructure *structure);
gboolean gst_structure_has_field (const GstStructure *structure,
const gchar *fieldname);
@ -122,6 +135,14 @@ gchar * gst_structure_to_string (const GstStructure
GstStructure * gst_structure_from_string (const gchar *string,
gchar **end);
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

View file

@ -1,6 +1,6 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wim.taymans@chello.be>
* 2004 Wim Taymans <wim@fluendo.com>
*
* gstsystemclock.c: Default clock, uses the system clock
*
@ -20,13 +20,12 @@
* Boston, MA 02111-1307, USA.
*/
#include <time.h>
#include "gst_private.h"
#include "gstinfo.h"
#include "gstsystemclock.h"
/* the one instance of the systemclock */
static GstClock *_the_system_clock = NULL;
static void gst_system_clock_class_init (GstSystemClockClass * klass);
@ -35,9 +34,15 @@ static void gst_system_clock_dispose (GObject * object);
static GstClockTime gst_system_clock_get_internal_time (GstClock * clock);
static guint64 gst_system_clock_get_resolution (GstClock * clock);
static GstClockEntryStatus gst_system_clock_wait (GstClock * clock,
static GstClockReturn gst_system_clock_id_wait (GstClock * clock,
GstClockEntry * entry);
static void gst_system_clock_unlock (GstClock * clock, GstClockEntry * entry);
static GstClockReturn gst_system_clock_id_wait_unlocked
(GstClock * clock, GstClockEntry * entry);
static GstClockReturn gst_system_clock_id_wait_async (GstClock * clock,
GstClockEntry * entry);
static void gst_system_clock_id_unschedule (GstClock * clock,
GstClockEntry * entry);
static void gst_system_clock_async_thread (GstClock * clock);
static GStaticMutex _gst_sysclock_mutex = G_STATIC_MUTEX_INIT;
@ -87,22 +92,43 @@ gst_system_clock_class_init (GstSystemClockClass * klass)
gstclock_class->get_internal_time = gst_system_clock_get_internal_time;
gstclock_class->get_resolution = gst_system_clock_get_resolution;
gstclock_class->wait = gst_system_clock_wait;
gstclock_class->unlock = gst_system_clock_unlock;
gstclock_class->wait = gst_system_clock_id_wait;
gstclock_class->wait_async = gst_system_clock_id_wait_async;
gstclock_class->unschedule = gst_system_clock_id_unschedule;
}
static void
gst_system_clock_init (GstSystemClock * clock)
{
clock->mutex = g_mutex_new ();
clock->cond = g_cond_new ();
GError *error = NULL;
GST_CLOCK_FLAGS (clock) =
GST_CLOCK_FLAG_CAN_DO_SINGLE_SYNC |
GST_CLOCK_FLAG_CAN_DO_SINGLE_ASYNC |
GST_CLOCK_FLAG_CAN_DO_PERIODIC_SYNC |
GST_CLOCK_FLAG_CAN_DO_PERIODIC_ASYNC;
GST_LOCK (clock);
clock->thread = g_thread_create ((GThreadFunc) gst_system_clock_async_thread,
clock, TRUE, &error);
if (error)
goto no_thread;
/* wait for it to spin up */
GST_CLOCK_WAIT (clock);
GST_UNLOCK (clock);
return;
no_thread:
{
g_warning ("could not create async clock thread: %s", error->message);
}
}
static void
gst_system_clock_dispose (GObject * object)
{
GstClock *clock = (GstClock *) object;
GstSystemClock *sysclock = (GstSystemClock *) object;
/* there are subclasses of GstSystemClock running around... */
if (_the_system_clock == clock) {
@ -111,19 +137,19 @@ gst_system_clock_dispose (GObject * object)
/* no parent dispose here, this is bad enough already */
} else {
G_OBJECT_CLASS (parent_class)->dispose (object);
/* FIXME: Notifying before freeing? */
g_cond_free (sysclock->cond);
g_mutex_free (sysclock->mutex);
}
}
/**
* gst_system_clock_obtain
*
* Get a handle to the default system clock.
* Get a handle to the default system clock. The refcount of the
* clock will be increased so you need to unref the clock after
* usage.
*
* Returns: the default clock.
*
* MT safe.
*/
GstClock *
gst_system_clock_obtain (void)
@ -164,6 +190,105 @@ have_clock:
return clock;
}
/* this thread reads the sorted clock entries from the queue.
*
* It waits on each of them and fires the callback when the timeout occurs.
*
* When an entry in the queue was canceled, it is simply skipped.
*
* When waiting for an entry, it can become canceled, in that case we don't
* call the callback but move to the next item in the queue.
*
* MT safe.
*/
static void
gst_system_clock_async_thread (GstClock * clock)
{
GstSystemClock *sysclock = GST_SYSTEM_CLOCK (clock);
GST_CAT_DEBUG (GST_CAT_CLOCK, "enter system clock thread");
GST_LOCK (clock);
/* signal spinup */
GST_CLOCK_SIGNAL (clock);
/* now enter our infinite loop */
while (!sysclock->stopping) {
GstClockEntry *entry;
GstClockReturn res;
/* check if something to be done */
while (clock->entries == NULL) {
GST_CAT_DEBUG (GST_CAT_CLOCK, "nothing to wait for");
/* wait for work to do */
GST_CLOCK_WAIT (clock);
GST_CAT_DEBUG (GST_CAT_CLOCK, "got signal");
/* clock was stopping, exit */
if (sysclock->stopping)
goto exit;
}
/* pick the next entry */
entry = clock->entries->data;
/* if it was unscheduled, just move on to the next entry */
if (entry->status == GST_CLOCK_UNSCHEDULED) {
GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p was unscheduled", entry);
goto next_entry;
}
/* now wait for the entry, we already hold the lock */
res = gst_system_clock_id_wait_unlocked (clock, (GstClockID) entry);
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);
}
if (entry->type == GST_CLOCK_ENTRY_PERIODIC) {
/* adjust time now */
entry->time += entry->interval;
/* and resort the list now */
clock->entries =
g_list_sort (clock->entries, gst_clock_id_compare_func);
/* and restart */
continue;
} else {
goto next_entry;
}
}
case GST_CLOCK_BUSY:
/* somebody unlocked the entry but is was not canceled, This means that
* either a new entry was added in front of the queue or some other entry
* was canceled. Whatever it is, pick the head entry of the list and
* continue waiting. */
GST_CAT_DEBUG (GST_CAT_CLOCK, "async entry %p needs restart", entry);
continue;
default:
GST_CAT_DEBUG (GST_CAT_CLOCK,
"strange result %d waiting for %p, skipping", res, entry);
goto next_entry;
}
next_entry:
/* we remove the current entry and unref it */
clock->entries = g_list_remove (clock->entries, entry);
gst_clock_id_unref ((GstClockID) entry);
}
exit:
/* signal exit */
GST_CLOCK_SIGNAL (clock);
GST_UNLOCK (clock);
GST_CAT_DEBUG (GST_CAT_CLOCK, "exit system clock thread");
}
/* MT safe */
static GstClockTime
gst_system_clock_get_internal_time (GstClock * clock)
{
@ -180,49 +305,128 @@ gst_system_clock_get_resolution (GstClock * clock)
return 1 * GST_USECOND;
}
static GstClockEntryStatus
gst_system_clock_wait (GstClock * clock, GstClockEntry * entry)
/* synchronously wait on the given GstClockEntry.
*
* We do this by blocking on the global clock GCond variable with
* the requested time as a timeout. This allows us to unblock the
* entry by signaling the GCond variable.
*
* Note that signaling the global GCond unlocks all waiting entries. So
* we need to check if an unlocked entry has changed when it unlocks.
*
* Entries that arrive too late are simply not waited on and a
* GST_CLOCK_EARLY result is returned.
*
* MT safe.
*/
static GstClockReturn
gst_system_clock_id_wait_unlocked (GstClock * clock, GstClockEntry * entry)
{
GstClockEntryStatus res;
GstClockTime current, target;
gint64 diff;
GstSystemClock *sysclock = GST_SYSTEM_CLOCK (clock);
GstClockTime real, current, target;
GstClockTimeDiff diff;
current = gst_clock_get_time (clock);
diff = GST_CLOCK_ENTRY_TIME (entry) - current;
if (diff + clock->max_diff < 0) {
GST_WARNING_OBJECT (clock, "clock is way behind: %" G_GINT64_FORMAT
"s (max allowed is %" G_GINT64_FORMAT "s", -diff, clock->max_diff);
return GST_CLOCK_ENTRY_EARLY;
}
/* need to call the overridden method */
real = GST_CLOCK_GET_CLASS (clock)->get_internal_time (clock);
target = GST_CLOCK_ENTRY_TIME (entry);
current = gst_clock_adjust_unlocked (clock, real);
diff = target - current;
target = gst_system_clock_get_internal_time (clock) + diff;
GST_CAT_DEBUG (GST_CAT_CLOCK, "real_target %" G_GUINT64_FORMAT
" target %" G_GUINT64_FORMAT
" now %" G_GUINT64_FORMAT, target, GST_CLOCK_ENTRY_TIME (entry), current);
GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p"
" target %" GST_TIME_FORMAT
" now %" GST_TIME_FORMAT
" real %" GST_TIME_FORMAT
" diff %" G_GINT64_FORMAT,
entry,
GST_TIME_ARGS (target),
GST_TIME_ARGS (current), GST_TIME_ARGS (real), diff);
if (((gint64) target) > 0) {
if (diff > 0) {
GTimeVal tv;
GST_TIME_TO_TIMEVAL (target, tv);
g_mutex_lock (sysclock->mutex);
g_cond_timed_wait (sysclock->cond, sysclock->mutex, &tv);
g_mutex_unlock (sysclock->mutex);
res = entry->status;
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;
}
}
} else {
res = GST_CLOCK_ENTRY_EARLY;
entry->status = GST_CLOCK_EARLY;
}
return res;
return entry->status;
}
static void
gst_system_clock_unlock (GstClock * clock, GstClockEntry * entry)
static GstClockReturn
gst_system_clock_id_wait (GstClock * clock, GstClockEntry * entry)
{
GstSystemClock *sysclock = GST_SYSTEM_CLOCK (clock);
GstClockReturn ret;
g_mutex_lock (sysclock->mutex);
g_cond_broadcast (sysclock->cond);
g_mutex_unlock (sysclock->mutex);
GST_LOCK (clock);
ret = gst_system_clock_id_wait_unlocked (clock, entry);
GST_UNLOCK (clock);
return ret;
}
/* Add an entry to the list of pending async waits. The entry is inserted
* in sorted order. If we inserted the entry at the head of the list, we
* need to signal the thread as it might either be waiting on it or waiting
* for a new entry.
*
* MT safe.
*/
static GstClockReturn
gst_system_clock_id_wait_async (GstClock * clock, GstClockEntry * entry)
{
GST_CAT_DEBUG (GST_CAT_CLOCK, "adding entry %p", entry);
GST_LOCK (clock);
/* need to take a ref */
gst_clock_id_ref ((GstClockID) entry);
/* insert the entry in sorted order */
clock->entries = g_list_insert_sorted (clock->entries, entry,
gst_clock_id_compare_func);
/* only need to send the signal if the entry was added to the
* front, else the thread is just waiting for another entry and
* will get to 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);
}

View file

@ -42,8 +42,9 @@ typedef struct _GstSystemClockClass GstSystemClockClass;
struct _GstSystemClock {
GstClock clock;
GMutex * mutex;
GCond * cond;
/*< private >*/
GThread *thread; /* thread for async notify */
gboolean stopping;
gpointer _gst_reserved[GST_PADDING];
};
@ -51,6 +52,7 @@ struct _GstSystemClock {
struct _GstSystemClockClass {
GstClockClass parent_class;
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};

View file

@ -446,7 +446,7 @@ typedef struct
GstTagCopyData;
static void
gst_tag_list_add_value_internal (GstStructure * list, GstTagMergeMode mode,
GQuark tag, GValue * value)
GQuark tag, const GValue * value)
{
GstTagInfo *info = gst_tag_lookup (tag);
const GValue *value2;
@ -500,7 +500,7 @@ gst_tag_list_add_value_internal (GstStructure * list, GstTagMergeMode mode,
}
}
static gboolean
gst_tag_list_copy_foreach (GQuark tag, GValue * value, gpointer user_data)
gst_tag_list_copy_foreach (GQuark tag, const GValue * value, gpointer user_data)
{
GstTagCopyData *copy = (GstTagCopyData *) user_data;
@ -770,7 +770,8 @@ typedef struct
}
TagForeachData;
static int
structure_foreach_wrapper (GQuark field_id, GValue * value, gpointer user_data)
structure_foreach_wrapper (GQuark field_id, const GValue * value,
gpointer user_data)
{
TagForeachData *data = (TagForeachData *) user_data;

View file

@ -132,7 +132,7 @@ gst_tag_setter_merge (GstTagSetter * setter, const GstTagList * list,
* @...: more tag / value pairs to set
*
* Adds the given tag / value pairs on the setter using the given merge mode.
* The list must be terminated with %NULL.
* The list must be terminated with GST_TAG_INVALID.
*/
void
gst_tag_setter_add (GstTagSetter * setter, GstTagMergeMode mode,
@ -156,7 +156,7 @@ gst_tag_setter_add (GstTagSetter * setter, GstTagMergeMode mode,
* @...: more tag / GValue pairs to set
*
* Adds the given tag / GValue pairs on the setter using the given merge mode.
* The list must be terminated with %NULL.
* The list must be terminated with GST_TAG_INVALID.
*/
void
gst_tag_setter_add_values (GstTagSetter * setter, GstTagMergeMode mode,
@ -180,7 +180,7 @@ gst_tag_setter_add_values (GstTagSetter * setter, GstTagMergeMode mode,
* @var_args: tag / value pairs to set
*
* Adds the given tag / value pairs on the setter using the given merge mode.
* The list must be terminated with %NULL.
* The list must be terminated with GST_TAG_INVALID.
*/
void
gst_tag_setter_add_valist (GstTagSetter * setter, GstTagMergeMode mode,
@ -206,7 +206,7 @@ gst_tag_setter_add_valist (GstTagSetter * setter, GstTagMergeMode mode,
* @var_args: tag / GValue pairs to set
*
* Adds the given tag / GValue pairs on the setter using the given merge mode.
* The list must be terminated with %NULL.
* The list must be terminated with GST_TAG_INVALID.
*/
void
gst_tag_setter_add_valist_values (GstTagSetter * setter, GstTagMergeMode mode,

View file

@ -446,7 +446,7 @@ typedef struct
GstTagCopyData;
static void
gst_tag_list_add_value_internal (GstStructure * list, GstTagMergeMode mode,
GQuark tag, GValue * value)
GQuark tag, const GValue * value)
{
GstTagInfo *info = gst_tag_lookup (tag);
const GValue *value2;
@ -500,7 +500,7 @@ gst_tag_list_add_value_internal (GstStructure * list, GstTagMergeMode mode,
}
}
static gboolean
gst_tag_list_copy_foreach (GQuark tag, GValue * value, gpointer user_data)
gst_tag_list_copy_foreach (GQuark tag, const GValue * value, gpointer user_data)
{
GstTagCopyData *copy = (GstTagCopyData *) user_data;
@ -770,7 +770,8 @@ typedef struct
}
TagForeachData;
static int
structure_foreach_wrapper (GQuark field_id, GValue * value, gpointer user_data)
structure_foreach_wrapper (GQuark field_id, const GValue * value,
gpointer user_data)
{
TagForeachData *data = (TagForeachData *) user_data;

View file

@ -132,7 +132,7 @@ gst_tag_setter_merge (GstTagSetter * setter, const GstTagList * list,
* @...: more tag / value pairs to set
*
* Adds the given tag / value pairs on the setter using the given merge mode.
* The list must be terminated with %NULL.
* The list must be terminated with GST_TAG_INVALID.
*/
void
gst_tag_setter_add (GstTagSetter * setter, GstTagMergeMode mode,
@ -156,7 +156,7 @@ gst_tag_setter_add (GstTagSetter * setter, GstTagMergeMode mode,
* @...: more tag / GValue pairs to set
*
* Adds the given tag / GValue pairs on the setter using the given merge mode.
* The list must be terminated with %NULL.
* The list must be terminated with GST_TAG_INVALID.
*/
void
gst_tag_setter_add_values (GstTagSetter * setter, GstTagMergeMode mode,
@ -180,7 +180,7 @@ gst_tag_setter_add_values (GstTagSetter * setter, GstTagMergeMode mode,
* @var_args: tag / value pairs to set
*
* Adds the given tag / value pairs on the setter using the given merge mode.
* The list must be terminated with %NULL.
* The list must be terminated with GST_TAG_INVALID.
*/
void
gst_tag_setter_add_valist (GstTagSetter * setter, GstTagMergeMode mode,
@ -206,7 +206,7 @@ gst_tag_setter_add_valist (GstTagSetter * setter, GstTagMergeMode mode,
* @var_args: tag / GValue pairs to set
*
* Adds the given tag / GValue pairs on the setter using the given merge mode.
* The list must be terminated with %NULL.
* The list must be terminated with GST_TAG_INVALID.
*/
void
gst_tag_setter_add_valist_values (GstTagSetter * setter, GstTagMergeMode mode,

View file

@ -233,7 +233,7 @@ gst_thread_dispose (GObject * object)
g_cond_free (thread->cond);
g_mutex_free (thread->iterate_lock);
gst_object_replace ((GstObject **) & GST_ELEMENT_SCHED (thread), NULL);
gst_object_replace ((GstObject **) & GST_ELEMENT_SCHEDULER (thread), NULL);
}
/**
@ -321,7 +321,9 @@ gst_thread_release_children_locks (GstThread * thread)
{
GstRealPad *peer = NULL;
GstElement *peerelement;
GList *elements = (GList *) gst_bin_get_list (GST_BIN (thread));
/* not MT safe but gstthread is going away soon */
GList *elements = (GList *) GST_BIN (thread)->children;
while (elements) {
GstElement *element = GST_ELEMENT (elements->data);
@ -354,7 +356,7 @@ gst_thread_release_children_locks (GstThread * thread)
if (!peerelement)
continue; /* FIXME: deal with case where there's no peer */
if (GST_ELEMENT_SCHED (peerelement) != GST_ELEMENT_SCHED (thread)) {
if (GST_ELEMENT_SCHEDULER (peerelement) != GST_ELEMENT_SCHEDULER (thread)) {
GST_LOG_OBJECT (thread, "element \"%s\" has pad cross sched boundary",
GST_ELEMENT_NAME (element));
GST_LOG_OBJECT (thread, "waking element \"%s\"",
@ -473,8 +475,9 @@ revert:
break;
case GST_STATE_PAUSED_TO_PLAYING:
{
/* FIXME: recurse into sub-bins */
GList *elements = (GList *) gst_bin_get_list (GST_BIN (thread));
/* FIXME: recurse into sub-bins. not MT safe but gstthread is going
* away soon. */
GList *elements = (GList *) GST_BIN (thread)->children;
while (elements) {
gst_element_enable_threadsafe_properties ((GstElement *) elements->
@ -491,7 +494,7 @@ revert:
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
elements = (GList *) gst_bin_get_list (GST_BIN (thread));
elements = (GList *) GST_BIN (thread)->children;
while (elements) {
gst_element_disable_threadsafe_properties ((GstElement *) elements->
@ -664,7 +667,7 @@ gst_thread_main_loop (void *arg)
g_private_set (gst_thread_current, thread);
/* set up the element's scheduler */
gst_scheduler_setup (GST_ELEMENT_SCHED (thread));
gst_scheduler_setup (GST_ELEMENT_SCHEDULER (thread));
GST_FLAG_UNSET (thread, GST_THREAD_STATE_REAPING);
GST_FLAG_UNSET (thread, GST_THREAD_STATE_WAITING);
@ -726,7 +729,7 @@ gst_thread_main_loop (void *arg)
/* we need to destroy the scheduler here because it might have
* mapped it's stack into the threads stack space */
sched = GST_ELEMENT_SCHED (thread);
sched = GST_ELEMENT_SCHEDULER (thread);
if (sched)
gst_scheduler_reset (sched);

View file

@ -98,7 +98,7 @@ gst_trash_stack_pop (GstTrashStack *stack)
* problem that arises when a pop and push of the same element happens
* right between when we read head->next and try to swing the new pointer
* into place. This is usually solved using a counter which makes it highly
* inlikely that we manage to grab the wrong head->next value.
* unlikely that we manage to grab the wrong head->next value.
*/
__asm__ __volatile__ (
" pushl %%ebx; \n\t"
@ -124,6 +124,7 @@ gst_trash_stack_pop (GstTrashStack *stack)
}
#else
#warning "using fallback trashstack implementation, performance may suffer"
/*
* generic implementation

View file

@ -94,7 +94,7 @@ gst_type_find_factory_dispose (GObject * object)
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (object);
if (factory->caps) {
gst_caps_free (factory->caps);
gst_caps_unref (factory->caps);
factory->caps = NULL;
}
if (factory->extensions) {

View file

@ -22,7 +22,7 @@
#include <glib.h>
G_BEGIN_DECLS
G_BEGIN_DECLS
typedef struct _GstObject GstObject;
typedef struct _GstObjectClass GstObjectClass;
@ -34,6 +34,10 @@ typedef struct _GstElement GstElement;
typedef struct _GstElementClass GstElementClass;
typedef struct _GstBin GstBin;
typedef struct _GstBinClass GstBinClass;
typedef struct _GstPipeline GstPipeline;
typedef struct _GstPipelineClass GstPipelineClass;
typedef struct _GstBus GstBus;
typedef struct _GstBusClass GstBusClass;
typedef struct _GstScheduler GstScheduler;
typedef struct _GstSchedulerClass GstSchedulerClass;
typedef struct _GstEvent GstEvent;
@ -68,7 +72,6 @@ typedef enum {
#define GST_PADDING 4
#define GST_PADDING_INIT { 0 }
G_END_DECLS
#endif /* __GST_TYPES_H__ */

File diff suppressed because it is too large Load diff

View file

@ -25,7 +25,7 @@
#define __GST_UTILS_H__
#include <glib.h>
#include <gst/gstelement.h>
#include <gst/gstbin.h>
G_BEGIN_DECLS
@ -224,6 +224,62 @@ type_as_function ## _get_type (void) \
#endif /* GST_HAVE_UNALIGNED_ACCESS */
void gst_object_default_error (GstObject * source,
GError * error, gchar * debug);
/* element functions */
GstFlowReturn gst_element_abort_preroll (GstElement *element);
GstFlowReturn gst_element_finish_preroll (GstElement *element, GstPad *pad);
GstPad* gst_element_get_compatible_pad (GstElement *element, GstPad *pad);
GstPad* gst_element_get_compatible_pad_filtered (GstElement *element, GstPad *pad,
const GstCaps *filtercaps);
GstPadTemplate* gst_element_get_compatible_pad_template (GstElement *element, GstPadTemplate *compattempl);
G_CONST_RETURN gchar* gst_element_state_get_name (GstElementState state);
gboolean gst_element_link (GstElement *src, GstElement *dest);
gboolean gst_element_link_many (GstElement *element_1,
GstElement *element_2, ...);
gboolean gst_element_link_filtered (GstElement *src, GstElement *dest,
const GstCaps *filtercaps);
void gst_element_unlink (GstElement *src, GstElement *dest);
void gst_element_unlink_many (GstElement *element_1,
GstElement *element_2, ...);
gboolean gst_element_link_pads (GstElement *src, const gchar *srcpadname,
GstElement *dest, const gchar *destpadname);
gboolean gst_element_link_pads_filtered (GstElement *src, const gchar *srcpadname,
GstElement *dest, const gchar *destpadname,
const GstCaps *filtercaps);
void gst_element_unlink_pads (GstElement *src, const gchar *srcpadname,
GstElement *dest, const gchar *destpadname);
/* element class functions */
void gst_element_class_install_std_props (GstElementClass * klass,
const gchar * first_name, ...);
/* pad functions */
gboolean gst_pad_can_link (GstPad *srcpad, GstPad *sinkpad);
gboolean gst_pad_can_link_filtered (GstPad *srcpad, GstPad *sinkpad, const GstCaps *filtercaps);
void gst_pad_use_fixed_caps (GstPad *pad);
GstCaps* gst_pad_get_fixed_caps_func (GstPad *pad);
GstCaps* gst_pad_proxy_getcaps (GstPad * pad);
gboolean gst_pad_proxy_setcaps (GstPad * pad, GstCaps * caps);
/* bin functions */
void gst_bin_add_many (GstBin *bin, GstElement *element_1, ...);
void gst_bin_remove_many (GstBin *bin, GstElement *element_1, ...);
/* buffer functions */
GstBuffer * gst_buffer_merge (GstBuffer * buf1, GstBuffer * buf2);
void gst_buffer_stamp (GstBuffer * dest, const GstBuffer * src);
void gst_buffer_stamp (GstBuffer * dest, const GstBuffer * src);
G_END_DECLS
#endif /* __GST_UTILS_H__ */

View file

@ -1343,7 +1343,7 @@ gst_value_deserialize_string (GValue * dest, const char *s)
if (!str)
return FALSE;
g_value_set_string_take_ownership (dest, str);
g_value_take_string (dest, str);
}
return TRUE;

View file

@ -13,6 +13,7 @@
#include "../gstinfo.h"
#include "../gsterror.h"
#include "../gsturi.h"
#include "../gstutils.h"
#include "../gstvalue.h"
#include "types.h"
@ -285,28 +286,56 @@ gst_parse_free_link (link_t *link)
g_slist_foreach (link->sink_pads, (GFunc) gst_parse_strfree, NULL);
g_slist_free (link->src_pads);
g_slist_free (link->sink_pads);
if (link->caps) gst_caps_free (link->caps);
if (link->caps) gst_caps_unref (link->caps);
gst_parse_link_free (link);
}
static void
gst_parse_element_lock (GstElement *element, gboolean lock)
{
GstPad *pad;
GList *walk = (GList *) gst_element_get_pad_list (element);
GstIterator *pads;
gboolean unlocked_peer = FALSE;
gboolean done = FALSE;
GList *walk;
if (gst_element_is_locked_state (element) == lock)
return;
return;
/* check if we have an unlocked peer */
for (; walk; walk = walk->next) {
pad = (GstPad *) GST_PAD_REALIZE (walk->data);
if (GST_PAD_IS_SINK (pad) && GST_PAD_PEER (pad) &&
!gst_element_is_locked_state (GST_PAD_PARENT (GST_PAD_PEER (pad)))) {
unlocked_peer = TRUE;
break;
pads = gst_element_iterate_pads (element);
while (!done) {
gpointer data;
switch (gst_iterator_next (pads, &data)) {
case GST_ITERATOR_OK:
{
GstPad *pad = GST_PAD_CAST (data);
pad = gst_pad_realize (pad);
if (GST_PAD_IS_SINK (pad) && GST_PAD_PEER (pad) &&
!gst_element_is_locked_state (GST_PAD_PARENT (GST_PAD_PEER (pad)))) {
unlocked_peer = TRUE;
done = TRUE;
}
gst_object_unref (GST_OBJECT (pad));
break;
}
case GST_ITERATOR_RESYNC:
unlocked_peer = FALSE;
gst_iterator_resync (pads);
break;
case GST_ITERATOR_DONE:
done = TRUE;
break;
default:
g_assert_not_reached ();
break;
}
}
}
gst_iterator_free (pads);
if (!(lock && unlocked_peer)) {
GST_CAT_DEBUG (GST_CAT_PIPELINE, "setting locked state on element");
gst_element_set_locked_state (element, lock);
@ -324,7 +353,7 @@ gst_parse_element_lock (GstElement *element, gboolean lock)
}
/* check if there are other pads to (un)lock */
walk = (GList *) gst_element_get_pad_list (element);
walk = (GList *) element->pads;
for (; walk; walk = walk->next) {
pad = (GstPad *) GST_PAD_REALIZE (walk->data);
if (GST_PAD_IS_SRC (pad) && GST_PAD_PEER (pad)) {
@ -351,7 +380,7 @@ gst_parse_found_pad (GstElement *src, GstPad *pad, gpointer data)
g_signal_handler_disconnect (src, link->signal_id);
g_free (link->src_pad);
g_free (link->sink_pad);
if (link->caps) gst_caps_free (link->caps);
if (link->caps) gst_caps_unref (link->caps);
if (!gst_element_is_locked_state (src))
gst_parse_element_lock (link->sink, FALSE);
g_free (link);
@ -362,7 +391,7 @@ static gboolean
gst_parse_perform_delayed_link (GstElement *src, const gchar *src_pad,
GstElement *sink, const gchar *sink_pad, GstCaps *caps)
{
GList *templs = gst_element_get_pad_template_list (src);
GList *templs = gst_element_class_get_pad_template_list (GST_ELEMENT_GET_CLASS (src));
for (; templs; templs = templs->next) {
GstPadTemplate *templ = (GstPadTemplate *) templs->data;

View file

@ -75,7 +75,7 @@ struct _GstSchedulerChain
#define GST_IS_BASIC_SCHEDULER_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASIC_SCHEDULER))
#define SCHED(element) GST_BASIC_SCHEDULER (GST_ELEMENT_SCHED (element))
#define SCHED(element) GST_BASIC_SCHEDULER (GST_ELEMENT_SCHEDULER (element))
typedef enum
{
@ -651,7 +651,7 @@ gst_basic_scheduler_cothreaded_chain (GstBin * bin, GstSchedulerChain * chain)
}
/* now we have to walk through the pads to set up their state */
pads = gst_element_get_pad_list (element);
pads = element->pads;
while (pads) {
GstPad *peerpad;
@ -1046,8 +1046,8 @@ gst_basic_scheduler_chain_recursive_add (GstSchedulerChain * chain,
if (GST_PAD_PEER (pad)) {
GST_DEBUG ("has peer %s:%s", GST_DEBUG_PAD_NAME (GST_PAD_PEER (pad)));
peerelement = GST_PAD_PARENT (GST_PAD_PEER (pad));
if (GST_ELEMENT_SCHED (GST_PAD_PARENT (pad)) ==
GST_ELEMENT_SCHED (peerelement)) {
if (GST_ELEMENT_SCHEDULER (GST_PAD_PARENT (pad)) ==
GST_ELEMENT_SCHEDULER (peerelement)) {
GST_DEBUG ("peer \"%s\" is valid for same chain",
GST_ELEMENT_NAME (peerelement));
gst_basic_scheduler_chain_recursive_add (chain, peerelement, remove);
@ -1247,7 +1247,7 @@ gst_basic_scheduler_pad_link (GstScheduler * sched, GstPad * srcpad,
GST_INFO ("have pad linked callback on %s:%s to %s:%s",
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
GST_DEBUG ("srcpad sched is %p, sinkpad sched is %p",
GST_ELEMENT_SCHED (srcelement), GST_ELEMENT_SCHED (sinkelement));
GST_ELEMENT_SCHEDULER (srcelement), GST_ELEMENT_SCHEDULER (sinkelement));
gst_basic_scheduler_chain_elements (bsched, srcelement, sinkelement);
}

View file

@ -1386,7 +1386,7 @@ get_group_schedule_function (int argc, char *argv[])
osched = group->chain->sched;
pads = gst_element_get_pad_list (entry);
pads = entry->pads;
GST_LOG ("executing get-based group %p", group);
@ -1725,7 +1725,7 @@ gst_opt_scheduler_state_transition (GstScheduler * sched, GstElement * element,
break;
case GST_STATE_PAUSED_TO_READY:
{
GList *pads = (GList *) gst_element_get_pad_list (element);
GList *pads = (GList *) element->pads;
g_list_foreach (pads, (GFunc) pad_clear_queued, NULL);
break;
@ -1994,7 +1994,7 @@ gst_opt_scheduler_add_element (GstScheduler * sched, GstElement * element)
* in _link, it can be overruled if need be */
/* FIXME: we should also do this when new pads on the element are created;
but there are no hooks, so we do it again in _link */
pads = gst_element_get_pad_list (element);
pads = element->pads;
while (pads) {
GstPad *pad = GST_PAD (pads->data);
@ -2327,7 +2327,7 @@ element_get_reachables_func (GstElement * element, GstOptSchedulerGroup * group,
result = g_list_prepend (result, element);
pads = gst_element_get_pad_list (element);
pads = element->pads;
while (pads) {
GstPad *pad = GST_PAD (pads->data);
GstPad *peer;

View file

@ -30,6 +30,7 @@
#include <gst/gstinfo.h>
#include <gst/gstplugin.h>
#include <gst/gstversion.h>
#include <gst/gstutils.h>
#include "bytestream.h"
GST_DEBUG_CATEGORY_STATIC (debug_bs);

View file

@ -188,7 +188,7 @@ gst_dp_header_from_buffer (const GstBuffer * buffer, GstDPHeaderFlag flags,
/* data flags */
/* we only copy KEY_UNIT,DELTA_UNIT and IN_CAPS flags */
flags_mask = GST_DATA_FLAG_SHIFT (GST_BUFFER_KEY_UNIT) |
flags_mask = GST_DATA_FLAG_SHIFT (GST_BUFFER_PREROLL) |
GST_DATA_FLAG_SHIFT (GST_BUFFER_IN_CAPS) |
GST_DATA_FLAG_SHIFT (GST_BUFFER_DELTA_UNIT);

View file

@ -887,7 +887,7 @@ gst_fakesrc_loop (GstElement * element)
src = GST_FAKESRC (element);
pads = gst_element_get_pad_list (element);
pads = element->pads;
while (pads) {
GstPad *pad = GST_PAD (pads->data);

View file

@ -203,14 +203,14 @@ gst_identity_init (GstIdentity * identity)
gst_element_add_pad (GST_ELEMENT (identity), identity->sinkpad);
gst_pad_set_chain_function (identity->sinkpad,
GST_DEBUG_FUNCPTR (gst_identity_chain));
gst_pad_set_link_function (identity->sinkpad, gst_pad_proxy_pad_link);
//gst_pad_set_link_function (identity->sinkpad, gst_pad_proxy_pad_link);
gst_pad_set_getcaps_function (identity->sinkpad, gst_pad_proxy_getcaps);
identity->srcpad =
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
"src");
gst_element_add_pad (GST_ELEMENT (identity), identity->srcpad);
gst_pad_set_link_function (identity->srcpad, gst_pad_proxy_pad_link);
//gst_pad_set_link_function (identity->srcpad, gst_pad_proxy_pad_link);
gst_pad_set_getcaps_function (identity->srcpad, gst_pad_proxy_getcaps);
identity->loop_based = DEFAULT_LOOP_BASED;

View file

@ -434,6 +434,8 @@ gst_queue_link_sink (GstPad * pad, const GstCaps * caps)
GST_QUEUE_MUTEX_UNLOCK;
}
link_ret = GST_PAD_LINK_OK;
#if 0
link_ret = gst_pad_proxy_pad_link (pad, caps);
if (GST_PAD_LINK_SUCCESSFUL (link_ret)) {
@ -441,6 +443,7 @@ gst_queue_link_sink (GstPad * pad, const GstCaps * caps)
* the pads become unnegotiated while we have buffers */
gst_caps_replace (&queue->negotiated_caps, gst_caps_copy (caps));
}
#endif
return link_ret;
}
@ -459,8 +462,10 @@ gst_queue_link_src (GstPad * pad, const GstCaps * caps)
}
return GST_PAD_LINK_REFUSED;
}
#if 0
link_ret = gst_pad_proxy_pad_link (pad, caps);
#endif
link_ret = GST_PAD_LINK_OK;
if (GST_PAD_LINK_SUCCESSFUL (link_ret)) {
/* we store an extra copy of the negotiated caps, just in case

View file

@ -141,8 +141,7 @@ gst_tee_init (GstTee * tee)
"sink");
gst_element_add_pad (GST_ELEMENT (tee), tee->sinkpad);
gst_pad_set_chain_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_tee_chain));
gst_pad_set_link_function (tee->sinkpad,
GST_DEBUG_FUNCPTR (gst_pad_proxy_pad_link));
//gst_pad_set_link_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_pad_proxy_pad_link));
gst_pad_set_getcaps_function (tee->sinkpad,
GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
@ -169,16 +168,15 @@ gst_tee_getcaps (GstPad * _pad)
GstPad *pad;
const GList *pads;
for (pads = gst_element_get_pad_list (GST_ELEMENT (tee));
pads != NULL; pads = pads->next) {
for (pads = GST_ELEMENT (tee)->pads; pads != NULL; pads = pads->next) {
pad = GST_PAD (pads->data);
if (pad == _pad)
continue;
tmp = gst_pad_get_allowed_caps (pad);
res = gst_caps_intersect (caps, tmp);
gst_caps_free (tmp);
gst_caps_free (caps);
gst_caps_unref (tmp);
gst_caps_unref (caps);
caps = res;
}
@ -195,8 +193,7 @@ gst_tee_link (GstPad * _pad, const GstCaps * caps)
GST_DEBUG_OBJECT (tee, "Forwarding link to all other pads");
for (pads = gst_element_get_pad_list (GST_ELEMENT (tee));
pads != NULL; pads = pads->next) {
for (pads = GST_ELEMENT (tee)->pads; pads != NULL; pads = pads->next) {
pad = GST_PAD (pads->data);
if (pad == _pad)
continue;
@ -231,7 +228,7 @@ gst_tee_request_new_pad (GstElement * element, GstPadTemplate * templ,
tee = GST_TEE (element);
/* try names in order and find one that's not in use atm */
pads = gst_element_get_pad_list (element);
pads = element->pads;
name = NULL;
while (!name) {
@ -335,7 +332,7 @@ gst_tee_chain (GstPad * pad, GstData * _data)
gst_buffer_ref_by_count (buf, GST_ELEMENT (tee)->numsrcpads - 1);
pads = gst_element_get_pad_list (GST_ELEMENT (tee));
pads = GST_ELEMENT (tee)->pads;
while (pads) {
GstPad *outpad = GST_PAD (pads->data);

View file

@ -350,7 +350,7 @@ free_entry (TypeFindEntry * entry)
free_entry_buffers (entry);
if (entry->caps)
gst_caps_free (entry->caps);
gst_caps_unref (entry->caps);
g_free (entry);
}
static void

112
po/nb.po
View file

@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: gstreamer 0.8.8\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2004-12-17 16:11+0100\n"
"POT-Creation-Date: 2005-03-03 13:45+0100\n"
"PO-Revision-Date: 2005-02-17 12:00+0100\n"
"Last-Translator: Kjartan Maraas <kmaraas@broadpark.no>\n"
"Language-Team: Norwegian Bokmaal <i18n-nb@lister.ping.uio.no>\n"
@ -27,7 +27,8 @@ msgid "Print available debug categories and exit"
msgstr "Skriv ut tilgjengelige feilsøkingskategorier og avslutt"
#: gst/gst.c:169
msgid "Default debug level from 1 (only error) to 5 (anything) or 0 for no output"
msgid ""
"Default debug level from 1 (only error) to 5 (anything) or 0 for no output"
msgstr ""
#: gst/gst.c:171
@ -35,7 +36,9 @@ msgid "LEVEL"
msgstr "NIVÅ"
#: gst/gst.c:173
msgid "Comma-separated list of category_name:level pairs to set specific levels for the individual categories. Example: GST_AUTOPLUG:5,GST_ELEMENT_*:3"
msgid ""
"Comma-separated list of category_name:level pairs to set specific levels for "
"the individual categories. Example: GST_AUTOPLUG:5,GST_ELEMENT_*:3"
msgstr ""
#: gst/gst.c:176
@ -63,7 +66,9 @@ msgid "PATHS"
msgstr "STIER"
#: gst/gst.c:191
msgid "Comma-separated list of plugins to preload in addition to the list stored in envronment variable GST_PLUGIN_PATH"
msgid ""
"Comma-separated list of plugins to preload in addition to the list stored in "
"environment variable GST_PLUGIN_PATH"
msgstr ""
#: gst/gst.c:193
@ -96,12 +101,12 @@ msgstr ""
msgid "Scheduler to use (default is '%s')"
msgstr "Planlegger som skal brukes («%s» er forvalgt)"
#: gst/gstelement.c:261
#: gst/gstelement.c:312
#, c-format
msgid "ERROR: from element %s: %s\n"
msgstr "FEIL: fra element %s: %s\n"
#: gst/gstelement.c:263
#: gst/gstelement.c:314
#, c-format
msgid ""
"Additional debug info:\n"
@ -115,7 +120,9 @@ msgid "GStreamer encountered a general core library error."
msgstr ""
#: gst/gsterror.c:58 gst/gsterror.c:95 gst/gsterror.c:115 gst/gsterror.c:145
msgid "GStreamer developers were too lazy to assign an error code to this error. Please file a bug."
msgid ""
"GStreamer developers were too lazy to assign an error code to this error. "
"Please file a bug."
msgstr ""
#: gst/gsterror.c:61
@ -158,7 +165,7 @@ msgstr ""
msgid "Internal GStreamer error: tag problem. File a bug."
msgstr ""
#: gst/gsterror.c:93 gst/gsterror.c:113 gst/gsterror.c:143
#: gst/gsterror.c:93
msgid "GStreamer encountered a general supporting library error."
msgstr ""
@ -170,6 +177,10 @@ msgstr "Kunne ikke initiere støttebibliotek."
msgid "Could not close supporting library."
msgstr "Kunne ikke lukke støttebibliotek."
#: gst/gsterror.c:113
msgid "GStreamer encountered a general resource error."
msgstr ""
#: gst/gsterror.c:117
msgid "Resource not found."
msgstr "Ressursen ble ikke funnet."
@ -214,6 +225,10 @@ msgstr "Kunne ikke synkronisere på ressurs."
msgid "Could not get/set settings from/on resource."
msgstr "Kunne ikke hente/sette innstillinger fra/på ressurs."
#: gst/gsterror.c:143
msgid "GStreamer encountered a general stream error."
msgstr ""
#: gst/gsterror.c:148
msgid "Element doesn't implement handling of this stream. Please file a bug."
msgstr ""
@ -290,7 +305,8 @@ msgstr "dato"
#: gst/gsttag.c:95
msgid "date the data was created (in Julian calendar days)"
msgstr "dato for oppretting av dataene (kalenderdager i den Julianske kalenderen)"
msgstr ""
"dato for oppretting av dataene (kalenderdager i den Julianske kalenderen)"
#: gst/gsttag.c:98
msgid "genre"
@ -551,8 +567,8 @@ msgstr "Kunne ikke åpne fil «%s» for skriving."
msgid "Error closing file \"%s\"."
msgstr "Feil ved lukking av fil «%s»."
#: gst/elements/gstfilesink.c:364 gst/elements/gstfilesink.c:399
#: gst/elements/gstfilesink.c:452
#: gst/elements/gstfilesink.c:364 gst/elements/gstfilesink.c:400
#: gst/elements/gstfilesink.c:453
#, c-format
msgid "Error while writing to file \"%s\"."
msgstr "Feil ved skriving til fil «%s»."
@ -668,112 +684,114 @@ msgstr ""
msgid "Print all elements"
msgstr ""
#: tools/gst-launch.c:107
#: tools/gst-launch.c:114
#, c-format
msgid "Execution ended after %s iterations (sum %s ns, average %s ns, min %s ns, max %s ns).\n"
msgid ""
"Execution ended after %s iterations (sum %s ns, average %s ns, min %s ns, "
"max %s ns).\n"
msgstr ""
#: tools/gst-launch.c:134
#: tools/gst-launch.c:141
msgid "Usage: gst-xmllaunch <file.xml> [ element.property=value ... ]\n"
msgstr ""
#: tools/gst-launch.c:142
#: tools/gst-launch.c:149
#, c-format
msgid "ERROR: parse of xml file '%s' failed.\n"
msgstr ""
#: tools/gst-launch.c:148
#: tools/gst-launch.c:155
#, c-format
msgid "ERROR: no toplevel pipeline element in file '%s'.\n"
msgstr ""
#: tools/gst-launch.c:155
#: tools/gst-launch.c:162
#, c-format
msgid "WARNING: only one toplevel element is supported at this time."
msgstr ""
#: tools/gst-launch.c:166
#: tools/gst-launch.c:173
#, c-format
msgid "ERROR: could not parse command line argument %d: %s.\n"
msgstr ""
#: tools/gst-launch.c:177
#: tools/gst-launch.c:184
#, c-format
msgid "WARNING: element named '%s' not found.\n"
msgstr ""
#: tools/gst-launch.c:316
#: tools/gst-launch.c:327
#, c-format
msgid "FOUND TAG : found by element \"%s\".\n"
msgstr ""
#: tools/gst-launch.c:403
#: tools/gst-launch.c:412
msgid "Output tags (also known as metadata)"
msgstr ""
#: tools/gst-launch.c:405
#: tools/gst-launch.c:414
msgid "Output status information and property notifications"
msgstr ""
#: tools/gst-launch.c:407
#: tools/gst-launch.c:416
msgid "Do not output status information of TYPE"
msgstr ""
#: tools/gst-launch.c:407
#: tools/gst-launch.c:416
msgid "TYPE1,TYPE2,..."
msgstr "TYPE1,TYPE2,..."
#: tools/gst-launch.c:410
#: tools/gst-launch.c:419
msgid "Save xml representation of pipeline to FILE and exit"
msgstr ""
#: tools/gst-launch.c:410
#: tools/gst-launch.c:419
msgid "FILE"
msgstr "FIL"
#: tools/gst-launch.c:413
#: tools/gst-launch.c:422
msgid "Do not install a fault handler"
msgstr ""
#: tools/gst-launch.c:415
#: tools/gst-launch.c:424
msgid "Print alloc trace (if enabled at compile time)"
msgstr ""
#: tools/gst-launch.c:417
#: tools/gst-launch.c:426
msgid "Number of times to iterate pipeline"
msgstr ""
#: tools/gst-launch.c:487
#, c-format
msgid "ERROR: pipeline could not be constructed: %s.\n"
msgstr ""
#: tools/gst-launch.c:491
#, c-format
msgid "ERROR: pipeline could not be constructed.\n"
msgstr ""
#: tools/gst-launch.c:495
#, c-format
msgid "WARNING: erroneous pipeline: %s\n"
msgstr ""
#: tools/gst-launch.c:496
#, c-format
msgid "ERROR: pipeline could not be constructed: %s.\n"
msgstr ""
#: tools/gst-launch.c:500
#, c-format
msgid "ERROR: pipeline could not be constructed.\n"
msgstr ""
#: tools/gst-launch.c:504
#, c-format
msgid "WARNING: erroneous pipeline: %s\n"
msgstr ""
#: tools/gst-launch.c:505
#, c-format
msgid " Trying to run anyway.\n"
msgstr ""
#: tools/gst-launch.c:523
#: tools/gst-launch.c:532
#, c-format
msgid "ERROR: the 'pipeline' element wasn't found.\n"
msgstr ""
#: tools/gst-launch.c:530
#: tools/gst-launch.c:539
#, c-format
msgid "RUNNING pipeline ...\n"
msgstr ""
#: tools/gst-launch.c:533
#: tools/gst-launch.c:542
#, c-format
msgid "ERROR: pipeline doesn't want to play.\n"
msgstr ""

119
po/ru.po
View file

@ -7,14 +7,15 @@ msgid ""
msgstr ""
"Project-Id-Version: gstreamer 0.8.8\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2004-12-17 16:11+0100\n"
"POT-Creation-Date: 2005-03-03 13:45+0100\n"
"PO-Revision-Date: 2005-02-12 23:37+0300\n"
"Last-Translator: Peter Astakhov <astakhovp@mail.ru>\n"
"Language-Team: Russian <ru@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1&&n%100!=11?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2);\n"
"Plural-Forms: nplurals=3; plural=(n%10==1&&n%100!=11?0:n%10>=2&&n%10<=4&&(n%"
"100<10||n%100>=20)?1:2);\n"
"X-Generator: KBabel 1.9.1\n"
#: gst/gst.c:160
@ -30,15 +31,20 @@ msgid "Print available debug categories and exit"
msgstr "Печатает доступные категории отладки и выходит"
#: gst/gst.c:169
msgid "Default debug level from 1 (only error) to 5 (anything) or 0 for no output"
msgstr "Уровень отладки по умолчанию от 1 (только ошибки) до 5(все) или 0 - ничего не печатать"
msgid ""
"Default debug level from 1 (only error) to 5 (anything) or 0 for no output"
msgstr ""
"Уровень отладки по умолчанию от 1 (только ошибки) до 5(все) или 0 - ничего "
"не печатать"
#: gst/gst.c:171
msgid "LEVEL"
msgstr "УРОВЕНЬ"
#: gst/gst.c:173
msgid "Comma-separated list of category_name:level pairs to set specific levels for the individual categories. Example: GST_AUTOPLUG:5,GST_ELEMENT_*:3"
msgid ""
"Comma-separated list of category_name:level pairs to set specific levels for "
"the individual categories. Example: GST_AUTOPLUG:5,GST_ELEMENT_*:3"
msgstr ""
#: gst/gst.c:176
@ -66,7 +72,9 @@ msgid "PATHS"
msgstr "ПУТИ"
#: gst/gst.c:191
msgid "Comma-separated list of plugins to preload in addition to the list stored in envronment variable GST_PLUGIN_PATH"
msgid ""
"Comma-separated list of plugins to preload in addition to the list stored in "
"environment variable GST_PLUGIN_PATH"
msgstr ""
#: gst/gst.c:193
@ -99,12 +107,12 @@ msgstr "список путей для загрузки расширений (р
msgid "Scheduler to use (default is '%s')"
msgstr ""
#: gst/gstelement.c:261
#: gst/gstelement.c:312
#, c-format
msgid "ERROR: from element %s: %s\n"
msgstr "ОШИБКА: из элемента %s: %s\n"
#: gst/gstelement.c:263
#: gst/gstelement.c:314
#, c-format
msgid ""
"Additional debug info:\n"
@ -118,7 +126,9 @@ msgid "GStreamer encountered a general core library error."
msgstr ""
#: gst/gsterror.c:58 gst/gsterror.c:95 gst/gsterror.c:115 gst/gsterror.c:145
msgid "GStreamer developers were too lazy to assign an error code to this error. Please file a bug."
msgid ""
"GStreamer developers were too lazy to assign an error code to this error. "
"Please file a bug."
msgstr ""
#: gst/gsterror.c:61
@ -161,7 +171,7 @@ msgstr ""
msgid "Internal GStreamer error: tag problem. File a bug."
msgstr ""
#: gst/gsterror.c:93 gst/gsterror.c:113 gst/gsterror.c:143
#: gst/gsterror.c:93
msgid "GStreamer encountered a general supporting library error."
msgstr ""
@ -173,6 +183,10 @@ msgstr "Не могу проинициализировать дополните
msgid "Could not close supporting library."
msgstr "Не могу закрыть дополнительную библиотеку."
#: gst/gsterror.c:113
msgid "GStreamer encountered a general resource error."
msgstr ""
#: gst/gsterror.c:117
msgid "Resource not found."
msgstr "Ресурс не найден."
@ -217,6 +231,10 @@ msgstr ""
msgid "Could not get/set settings from/on resource."
msgstr ""
#: gst/gsterror.c:143
msgid "GStreamer encountered a general stream error."
msgstr ""
#: gst/gsterror.c:148
msgid "Element doesn't implement handling of this stream. Please file a bug."
msgstr ""
@ -554,8 +572,8 @@ msgstr ""
msgid "Error closing file \"%s\"."
msgstr ""
#: gst/elements/gstfilesink.c:364 gst/elements/gstfilesink.c:399
#: gst/elements/gstfilesink.c:452
#: gst/elements/gstfilesink.c:364 gst/elements/gstfilesink.c:400
#: gst/elements/gstfilesink.c:453
#, c-format
msgid "Error while writing to file \"%s\"."
msgstr ""
@ -671,112 +689,115 @@ msgstr ""
msgid "Print all elements"
msgstr "Печатать все элементы"
#: tools/gst-launch.c:107
#: tools/gst-launch.c:114
#, c-format
msgid "Execution ended after %s iterations (sum %s ns, average %s ns, min %s ns, max %s ns).\n"
msgid ""
"Execution ended after %s iterations (sum %s ns, average %s ns, min %s ns, "
"max %s ns).\n"
msgstr ""
#: tools/gst-launch.c:134
#: tools/gst-launch.c:141
msgid "Usage: gst-xmllaunch <file.xml> [ element.property=value ... ]\n"
msgstr "Использование: gst-xmllaunch <файл.xml> [ элемент.поле=значение ... ]\n"
msgstr ""
"Использование: gst-xmllaunch <файл.xml> [ элемент.поле=значение ... ]\n"
#: tools/gst-launch.c:142
#: tools/gst-launch.c:149
#, c-format
msgid "ERROR: parse of xml file '%s' failed.\n"
msgstr "ОШИБКА: не могу разобрать xml файл '%s'.\n"
#: tools/gst-launch.c:148
#: tools/gst-launch.c:155
#, c-format
msgid "ERROR: no toplevel pipeline element in file '%s'.\n"
msgstr ""
#: tools/gst-launch.c:155
#: tools/gst-launch.c:162
#, c-format
msgid "WARNING: only one toplevel element is supported at this time."
msgstr ""
#: tools/gst-launch.c:166
#: tools/gst-launch.c:173
#, c-format
msgid "ERROR: could not parse command line argument %d: %s.\n"
msgstr "ОШИБКА: не могу разобрать аргумент командной строки %d: %s.\n"
#: tools/gst-launch.c:177
#: tools/gst-launch.c:184
#, c-format
msgid "WARNING: element named '%s' not found.\n"
msgstr "ПРЕДУПРЕЖДЕНИЕ: элемент '%s' не найден.\n"
#: tools/gst-launch.c:316
#: tools/gst-launch.c:327
#, c-format
msgid "FOUND TAG : found by element \"%s\".\n"
msgstr ""
#: tools/gst-launch.c:403
#: tools/gst-launch.c:412
msgid "Output tags (also known as metadata)"
msgstr "Выводить тэги (такжи называемые 'метаданные')"
#: tools/gst-launch.c:405
#: tools/gst-launch.c:414
msgid "Output status information and property notifications"
msgstr ""
#: tools/gst-launch.c:407
#: tools/gst-launch.c:416
msgid "Do not output status information of TYPE"
msgstr ""
#: tools/gst-launch.c:407
#: tools/gst-launch.c:416
msgid "TYPE1,TYPE2,..."
msgstr "ТИП1, ТИП2,..."
#: tools/gst-launch.c:410
#: tools/gst-launch.c:419
msgid "Save xml representation of pipeline to FILE and exit"
msgstr ""
#: tools/gst-launch.c:410
#: tools/gst-launch.c:419
msgid "FILE"
msgstr "ФАЙЛ"
#: tools/gst-launch.c:413
#: tools/gst-launch.c:422
msgid "Do not install a fault handler"
msgstr "Не устанавливать ошибочный обработчик"
#: tools/gst-launch.c:415
#: tools/gst-launch.c:424
msgid "Print alloc trace (if enabled at compile time)"
msgstr ""
#: tools/gst-launch.c:417
#: tools/gst-launch.c:426
msgid "Number of times to iterate pipeline"
msgstr ""
#: tools/gst-launch.c:487
#, c-format
msgid "ERROR: pipeline could not be constructed: %s.\n"
msgstr ""
#: tools/gst-launch.c:491
#, c-format
msgid "ERROR: pipeline could not be constructed.\n"
msgstr ""
#: tools/gst-launch.c:495
#, c-format
msgid "WARNING: erroneous pipeline: %s\n"
msgstr ""
#: tools/gst-launch.c:496
#, c-format
msgid "ERROR: pipeline could not be constructed: %s.\n"
msgstr ""
#: tools/gst-launch.c:500
#, c-format
msgid "ERROR: pipeline could not be constructed.\n"
msgstr ""
#: tools/gst-launch.c:504
#, c-format
msgid "WARNING: erroneous pipeline: %s\n"
msgstr ""
#: tools/gst-launch.c:505
#, c-format
msgid " Trying to run anyway.\n"
msgstr " Все равно пытаюсь запустить.\n"
#: tools/gst-launch.c:523
#: tools/gst-launch.c:532
#, c-format
msgid "ERROR: the 'pipeline' element wasn't found.\n"
msgstr ""
#: tools/gst-launch.c:530
#: tools/gst-launch.c:539
#, c-format
msgid "RUNNING pipeline ...\n"
msgstr ""
#: tools/gst-launch.c:533
#: tools/gst-launch.c:542
#, c-format
msgid "ERROR: pipeline doesn't want to play.\n"
msgstr ""

View file

@ -187,7 +187,7 @@ main (int argc, char *argv[])
gst_element_set_state (main_bin, GST_STATE_PLAYING);
/* write out the schedule */
gst_scheduler_show (GST_ELEMENT_SCHED (main_bin));
gst_scheduler_show (GST_ELEMENT_SCHEDULER (main_bin));
playing = TRUE;
j = 0;

View file

@ -1,6 +1,8 @@
#include <stdlib.h>
#include <gst/gst.h>
static GMainLoop *loop;
/* eos will be called when the src element has an end of stream */
void
eos (GstElement * element, gpointer data)
@ -12,7 +14,8 @@ eos (GstElement * element, gpointer data)
/* stop the bin */
gst_element_set_state (GST_ELEMENT (thread), GST_STATE_NULL);
gst_main_quit ();
g_main_loop_quit (loop);
g_main_loop_unref (loop);
}
int
@ -68,7 +71,7 @@ main (int argc, char *argv[])
/* start playing */
gst_element_set_state (GST_ELEMENT (thread), GST_STATE_PLAYING);
gst_main ();
loop = g_main_loop_new (NULL, FALSE);
gst_object_unref (GST_OBJECT (thread));

View file

@ -15,8 +15,6 @@ eos (GstElement * element, gpointer data)
/* stop the bin */
gst_element_set_state (GST_ELEMENT (thread), GST_STATE_NULL);
gst_main_quit ();
}
int

View file

@ -91,7 +91,7 @@ main (int argc, char *argv[])
padtemplate->name_template);
}
pads = gst_element_get_pad_list (element);
pads = element->pads;
while (pads) {
pad = (GstPad *) (pads->data);
pads = g_list_next (pads);

View file

@ -54,7 +54,7 @@ n_print (const char *format, ...)
}
static gboolean
print_field (GQuark field, GValue * value, gpointer pfx)
print_field (GQuark field, const GValue * value, gpointer pfx)
{
gchar *str = gst_value_serialize (value);
@ -505,18 +505,10 @@ print_element_flag_info (GstElement * element)
n_print ("\n");
n_print ("Element Flags:\n");
if (GST_FLAG_IS_SET (element, GST_ELEMENT_COMPLEX)) {
n_print (" GST_ELEMENT_COMPLEX\n");
have_flags = TRUE;
}
if (GST_FLAG_IS_SET (element, GST_ELEMENT_DECOUPLED)) {
n_print (" GST_ELEMENT_DECOUPLED\n");
have_flags = TRUE;
}
if (GST_FLAG_IS_SET (element, GST_ELEMENT_THREAD_SUGGESTED)) {
n_print (" GST_ELEMENT_THREADSUGGESTED\n");
have_flags = TRUE;
}
if (GST_FLAG_IS_SET (element, GST_ELEMENT_EVENT_AWARE)) {
n_print (" GST_ELEMENT_EVENT_AWARE\n");
have_flags = TRUE;
@ -535,10 +527,6 @@ print_element_flag_info (GstElement * element)
n_print (" GST_BIN_SELF_SCHEDULABLE\n");
have_flags = TRUE;
}
if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_PREFER_COTHREADS)) {
n_print (" GST_BIN_FLAG_PREFER_COTHREADS\n");
have_flags = TRUE;
}
if (!have_flags)
n_print (" no flags set\n");
}
@ -635,7 +623,7 @@ print_pad_info (GstElement * element)
return;
}
pads = gst_element_get_pad_list (element);
pads = element->pads;
while (pads) {
pad = GST_PAD (pads->data);
pads = g_list_next (pads);
@ -854,7 +842,7 @@ print_children_info (GstElement * element)
if (!GST_IS_BIN (element))
return;
children = (GList *) gst_bin_get_list (GST_BIN (element));
children = (GList *) GST_BIN (element)->children;
if (children) {
n_print ("\n");
g_print ("Children:\n");

View file

@ -69,6 +69,7 @@ static gboolean caught_intr = FALSE;
static gboolean caught_error = FALSE;
static gboolean need_new_state = FALSE;
static GstElementState new_state;
static GMainLoop *loop;
gboolean
idle_func (gpointer data)
@ -101,7 +102,8 @@ idle_func (gpointer data)
char *s_min;
char *s_max;
gst_main_quit ();
g_main_loop_quit (loop);
g_main_loop_unref (loop);
/* We write these all to strings first because
* G_GUINT64_FORMAT and gettext mix very poorly */
@ -544,11 +546,12 @@ main (int argc, char *argv[])
goto end;
}
s_clock = gst_bin_get_clock (GST_BIN (pipeline));
s_clock = gst_element_get_clock (GST_ELEMENT (pipeline));
if (!GST_FLAG_IS_SET (GST_OBJECT (pipeline), GST_BIN_SELF_SCHEDULABLE)) {
g_idle_add (idle_func, pipeline);
gst_main ();
loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (loop);
} else {
g_print ("Waiting for the state change... ");
gst_element_wait_state_change (pipeline);

View file

@ -12,6 +12,7 @@ static guint64 sum = 0;
static guint64 min = G_MAXINT64;
static guint64 max = 0;
static GstClock *s_clock;
static GMainLoop *loop;
gboolean
idle_func (gpointer data)
@ -36,7 +37,8 @@ idle_func (gpointer data)
max = MAX (max, diff);
if (!busy) {
gst_main_quit ();
g_main_loop_quit (loop);
g_main_loop_unref (loop);
/*
g_print ("execution ended after %llu iterations (sum %llu ns, average %llu ns, min %llu ns, max %llu ns)\n",
iterations, sum, sum/iterations, min, max);
@ -127,7 +129,8 @@ main (int argc, char *argv[])
if (!GST_FLAG_IS_SET (GST_OBJECT (pipeline), GST_BIN_SELF_SCHEDULABLE)) {
g_idle_add (idle_func, pipeline);
gst_main ();
loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (loop);
} else {
gst_element_wait_state_change (pipeline);
}

View file

@ -533,15 +533,9 @@ print_element_info (GstElementFactory * factory)
PUT_END_TAG (1, "pad-templates");
PUT_START_TAG (1, "element-flags");
if (GST_FLAG_IS_SET (element, GST_ELEMENT_COMPLEX)) {
PUT_ESCAPED (2, "flag", "GST_ELEMENT_COMPLEX");
}
if (GST_FLAG_IS_SET (element, GST_ELEMENT_DECOUPLED)) {
PUT_ESCAPED (2, "flag", "GST_ELEMENT_DECOUPLED");
}
if (GST_FLAG_IS_SET (element, GST_ELEMENT_THREAD_SUGGESTED)) {
PUT_ESCAPED (2, "flag", "GST_ELEMENT_THREADSUGGESTED");
}
if (GST_FLAG_IS_SET (element, GST_ELEMENT_EVENT_AWARE)) {
PUT_ESCAPED (2, "flag", "GST_ELEMENT_EVENT_AWARE");
}
@ -556,9 +550,6 @@ print_element_info (GstElementFactory * factory)
if (GST_FLAG_IS_SET (element, GST_BIN_SELF_SCHEDULABLE)) {
PUT_ESCAPED (2, "flag", "GST_BIN_SELF_SCHEDULABLE");
}
if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_PREFER_COTHREADS)) {
PUT_ESCAPED (2, "flag", "GST_BIN_FLAG_PREFER_COTHREADS");
}
PUT_END_TAG (1, "bin-flags");
}
@ -602,7 +593,7 @@ print_element_info (GstElementFactory * factory)
if (element->numpads) {
const GList *pads;
pads = gst_element_get_pad_list (element);
pads = element->pads;
while (pads) {
pad = GST_PAD (pads->data);
pads = g_list_next (pads);
@ -683,7 +674,7 @@ print_element_info (GstElementFactory * factory)
/* for compound elements */
if (GST_IS_BIN (element)) {
PUT_START_TAG (1, "children");
children = (GList *) gst_bin_get_list (GST_BIN (element));
children = (GList *) GST_BIN (element)->children;
while (children) {
child = GST_ELEMENT (children->data);
children = g_list_next (children);