mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 19:51:11 +00:00
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:
parent
d5e9b91e0a
commit
c47dc4d853
89 changed files with 6018 additions and 3263 deletions
215
ChangeLog
215
ChangeLog
|
@ -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:
|
||||
|
|
19
Makefile.am
19
Makefile.am
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
|
381
docs/design/part-MT-refcounting.txt
Normal file
381
docs/design/part-MT-refcounting.txt
Normal 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);
|
|
@ -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
|
||||
-----+ +---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
487
docs/design/part-relations.txt
Normal file
487
docs/design/part-relations.txt
Normal 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
71
gst/gst.c
71
gst/gst.c
|
@ -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
|
||||
|
|
|
@ -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__ */
|
||||
|
|
566
gst/gstbin.c
566
gst/gstbin.c
|
@ -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);
|
||||
|
||||
|
|
62
gst/gstbin.h
62
gst/gstbin.h
|
@ -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 */
|
||||
|
|
172
gst/gstbuffer.c
172
gst/gstbuffer.c
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
451
gst/gstcaps.c
451
gst/gstcaps.c
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
531
gst/gstclock.c
531
gst/gstclock.c
|
@ -1,6 +1,7 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
* 2004 Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* gstclock.c: Clock subsystem for maintaining time sync
|
||||
*
|
||||
|
@ -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;
|
||||
|
|
104
gst/gstclock.h
104
gst/gstclock.h
|
@ -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
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
17
gst/gstcpu.c
17
gst/gstcpu.c
|
@ -28,6 +28,7 @@
|
|||
#include "gstcpu.h"
|
||||
#include "gstinfo.h"
|
||||
|
||||
static GStaticMutex _cpu_mutex = G_STATIC_MUTEX_INIT;
|
||||
static guint32 _gst_cpu_flags = 0;
|
||||
|
||||
#if defined(HAVE_CPU_I386) && defined(__GNUC__)
|
||||
|
@ -89,7 +90,9 @@ _gst_cpu_initialize_i386 (gulong * flags, GString * featurelist)
|
|||
{
|
||||
gboolean AMD;
|
||||
gulong eax = 0, ebx = 0, ecx = 0, edx = 0;
|
||||
gboolean res = FALSE;
|
||||
|
||||
g_static_mutex_lock (&_cpu_mutex);
|
||||
gst_cpuid_i386 (0, &eax, &ebx, &ecx, &edx);
|
||||
|
||||
AMD = (ebx == 0x68747541) && (ecx == 0x444d4163) && (edx == 0x69746e65);
|
||||
|
@ -124,13 +127,21 @@ _gst_cpu_initialize_i386 (gulong * flags, GString * featurelist)
|
|||
}
|
||||
*flags = eax;
|
||||
if (_gst_cpu_flags)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
res = TRUE;
|
||||
g_static_mutex_unlock (&_cpu_mutex);
|
||||
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
GstCPUFlags
|
||||
gst_cpu_get_flags (void)
|
||||
{
|
||||
return _gst_cpu_flags;
|
||||
GstCPUFlags res;
|
||||
|
||||
g_static_mutex_lock (&_cpu_mutex);
|
||||
res = _gst_cpu_flags;
|
||||
g_static_mutex_unlock (&_cpu_mutex);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
1527
gst/gstelement.c
1527
gst/gstelement.c
File diff suppressed because it is too large
Load diff
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
512
gst/gstobject.c
512
gst/gstobject.c
|
@ -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;
|
||||
|
|
113
gst/gstobject.h
113
gst/gstobject.h
|
@ -1,6 +1,7 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
* 2005 Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* gstobject.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,
|
||||
|
|
773
gst/gstpad.c
773
gst/gstpad.c
File diff suppressed because it is too large
Load diff
73
gst/gstpad.h
73
gst/gstpad.h
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ struct _GstPluginFeatureClass {
|
|||
|
||||
void (*unload_thyself) (GstPluginFeature *feature);
|
||||
|
||||
/*< private >*/
|
||||
gpointer _gst_reserved[GST_PADDING];
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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__ */
|
||||
|
|
1353
gst/gstutils.c
1353
gst/gstutils.c
File diff suppressed because it is too large
Load diff
|
@ -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__ */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
112
po/nb.po
|
@ -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
119
po/ru.po
|
@ -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 ""
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue