mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-09-28 23:02:22 +00:00
More MT fixes, added design document describing refcounting policies used in GStreamer and locking involved.
Original commit message from CVS: * docs/design/part-MT-refcounting.txt: * docs/design/part-conventions.txt: * gst/gstbin.c: (gst_bin_set_index), (gst_bin_set_clock), (gst_bin_add_func), (gst_bin_remove_func), (gst_bin_iterate_elements), (gst_bin_change_state), (gst_bin_dispose), (gst_bin_get_by_name_recurse_up): * gst/gstcaps.c: * gst/gstelement.c: (gst_element_add_pad), (gst_element_remove_pad), (pad_compare_name), (gst_element_get_static_pad), (gst_element_get_request_pad), (gst_element_get_pad), (gst_element_iterate_pads), (gst_element_class_get_pad_template_list), (gst_element_class_get_pad_template), (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_post_message), (gst_element_set_locked_state), (gst_element_get_state), (gst_element_set_state), (gst_element_pads_activate), (gst_element_dispose), (gst_element_set_manager_func), (gst_element_get_manager): * gst/gstelement.h: * gst/gstiterator.c: (gst_iterator_new), (gst_list_iterator_next), (gst_list_iterator_resync), (gst_list_iterator_free), (gst_iterator_new_list): * gst/gstiterator.h: * gst/gstmessage.c: (_gst_message_copy): * 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_dispatch_properties_changed), (gst_object_set_name), (gst_object_set_parent), (gst_object_get_parent), (gst_object_unparent), (gst_object_check_uniqueness), (gst_object_get_path_string): * gst/gstobject.h: * gst/gstpad.c: (gst_pad_dispose), (gst_pad_set_active), (gst_pad_is_active), (gst_pad_set_blocked_async), (gst_pad_is_blocked), (gst_pad_unlink), (gst_pad_is_linked), (gst_pad_link_prepare_filtered), (gst_pad_link_filtered), (gst_pad_get_real_parent), (gst_pad_relink_filtered), (gst_pad_get_peer), (gst_pad_realize), (gst_pad_get_allowed_caps), (gst_pad_alloc_buffer), (gst_pad_push), (gst_pad_pull), (gst_pad_pull_range), (gst_pad_push_event): * gst/gstpad.h: * gst/gstpipeline.c: (gst_pipeline_init), (gst_pipeline_dispose), (is_eos), (pipeline_bus_handler): * gst/gstutils.c: (gst_element_get_compatible_pad_filtered), (gst_element_link_pads_filtered), (gst_element_unlink): * gst/parse/grammar.y: * tools/gst-compprep.c: (main): * tools/gst-inspect.c: (print_pad_info): * tools/gst-launch.c: (main): * tools/gst-xmlinspect.c: (print_element_info): More MT fixes, added design document describing refcounting policies used in GStreamer and locking involved. Fixed unsafe ghostpad dereffing. Removed old unsafe methods.
This commit is contained in:
parent
5b1065d625
commit
767d9e4681
24 changed files with 1746 additions and 1393 deletions
60
ChangeLog
60
ChangeLog
|
@ -1,3 +1,63 @@
|
||||||
|
2004-12-13 Wim Taymans <wim@fluendo.com>
|
||||||
|
|
||||||
|
* docs/design/part-MT-refcounting.txt:
|
||||||
|
* docs/design/part-conventions.txt:
|
||||||
|
* gst/gstbin.c: (gst_bin_set_index), (gst_bin_set_clock),
|
||||||
|
(gst_bin_add_func), (gst_bin_remove_func),
|
||||||
|
(gst_bin_iterate_elements), (gst_bin_change_state),
|
||||||
|
(gst_bin_dispose), (gst_bin_get_by_name_recurse_up):
|
||||||
|
* gst/gstcaps.c:
|
||||||
|
* gst/gstelement.c: (gst_element_add_pad),
|
||||||
|
(gst_element_remove_pad), (pad_compare_name),
|
||||||
|
(gst_element_get_static_pad), (gst_element_get_request_pad),
|
||||||
|
(gst_element_get_pad), (gst_element_iterate_pads),
|
||||||
|
(gst_element_class_get_pad_template_list),
|
||||||
|
(gst_element_class_get_pad_template), (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_post_message),
|
||||||
|
(gst_element_set_locked_state), (gst_element_get_state),
|
||||||
|
(gst_element_set_state), (gst_element_pads_activate),
|
||||||
|
(gst_element_dispose), (gst_element_set_manager_func),
|
||||||
|
(gst_element_get_manager):
|
||||||
|
* gst/gstelement.h:
|
||||||
|
* gst/gstiterator.c: (gst_iterator_new), (gst_list_iterator_next),
|
||||||
|
(gst_list_iterator_resync), (gst_list_iterator_free),
|
||||||
|
(gst_iterator_new_list):
|
||||||
|
* gst/gstiterator.h:
|
||||||
|
* gst/gstmessage.c: (_gst_message_copy):
|
||||||
|
* 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_dispatch_properties_changed), (gst_object_set_name),
|
||||||
|
(gst_object_set_parent), (gst_object_get_parent),
|
||||||
|
(gst_object_unparent), (gst_object_check_uniqueness),
|
||||||
|
(gst_object_get_path_string):
|
||||||
|
* gst/gstobject.h:
|
||||||
|
* gst/gstpad.c: (gst_pad_dispose), (gst_pad_set_active),
|
||||||
|
(gst_pad_is_active), (gst_pad_set_blocked_async),
|
||||||
|
(gst_pad_is_blocked), (gst_pad_unlink), (gst_pad_is_linked),
|
||||||
|
(gst_pad_link_prepare_filtered), (gst_pad_link_filtered),
|
||||||
|
(gst_pad_get_real_parent), (gst_pad_relink_filtered),
|
||||||
|
(gst_pad_get_peer), (gst_pad_realize), (gst_pad_get_allowed_caps),
|
||||||
|
(gst_pad_alloc_buffer), (gst_pad_push), (gst_pad_pull),
|
||||||
|
(gst_pad_pull_range), (gst_pad_push_event):
|
||||||
|
* gst/gstpad.h:
|
||||||
|
* gst/gstpipeline.c: (gst_pipeline_init), (gst_pipeline_dispose),
|
||||||
|
(is_eos), (pipeline_bus_handler):
|
||||||
|
* gst/gstutils.c: (gst_element_get_compatible_pad_filtered),
|
||||||
|
(gst_element_link_pads_filtered), (gst_element_unlink):
|
||||||
|
* gst/parse/grammar.y:
|
||||||
|
* tools/gst-compprep.c: (main):
|
||||||
|
* tools/gst-inspect.c: (print_pad_info):
|
||||||
|
* tools/gst-launch.c: (main):
|
||||||
|
* tools/gst-xmlinspect.c: (print_element_info):
|
||||||
|
More MT fixes, added design document describing refcounting
|
||||||
|
policies used in GStreamer and locking involved.
|
||||||
|
Fixed unsafe ghostpad dereffing.
|
||||||
|
Removed old unsafe methods.
|
||||||
|
|
||||||
2004-12-10 Wim Taymans <wim@fluendo.com>
|
2004-12-10 Wim Taymans <wim@fluendo.com>
|
||||||
|
|
||||||
* docs/design/part-MT-refcounting.txt:
|
* docs/design/part-MT-refcounting.txt:
|
||||||
|
|
|
@ -208,6 +208,9 @@ Objects
|
||||||
GST_UNLOCK (pad);
|
GST_UNLOCK (pad);
|
||||||
... use peer ...
|
... 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
|
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
|
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.
|
to include the operations on the peer.
|
||||||
|
@ -219,12 +222,12 @@ Objects
|
||||||
public fields manually.
|
public fields manually.
|
||||||
|
|
||||||
All accessor methods that return an object should increase the refcount of the returned
|
All accessor methods that return an object should increase the refcount of the returned
|
||||||
object. The called should _unref the object after usage. Each method should state this
|
object. The called should _unref() the object after usage. Each method should state this
|
||||||
refcounting policy in the documentation.
|
refcounting policy in the documentation.
|
||||||
|
|
||||||
* Accessing lists
|
* Accessing lists
|
||||||
|
|
||||||
If the object property is a list concurrent list iteration is needed to get the
|
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
|
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
|
of a list. The list and the cookie are protected by the same lock. Each update to
|
||||||
a list requires the following actions:
|
a list requires the following actions:
|
||||||
|
@ -286,7 +289,33 @@ Objects
|
||||||
|
|
||||||
* GstIterator
|
* GstIterator
|
||||||
|
|
||||||
GstIterator provides an easier way of retrieving elements in a concurrent list. See
|
GstIterator provides an easier way of retrieving elements in a concurrent list.
|
||||||
the documentation of the GstIterator class.
|
The followgin 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);
|
||||||
|
|
|
@ -31,3 +31,53 @@ element flags should be cross-checked with the header, as there are currently tw
|
||||||
_FLAGS_ in the middle.
|
_FLAGS_ in the middle.
|
||||||
|
|
||||||
FIXME: check flags for consistency.
|
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
|
||||||
|
-----+ +---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
138
gst/gstbin.c
138
gst/gstbin.c
|
@ -258,36 +258,34 @@ gst_bin_add_func (GstBin * bin, GstElement * element)
|
||||||
GstPipeline *manager;
|
GstPipeline *manager;
|
||||||
gchar *elem_name;
|
gchar *elem_name;
|
||||||
|
|
||||||
GST_LOCK (element);
|
|
||||||
/* the element must not already have a parent */
|
|
||||||
if (G_UNLIKELY (GST_ELEMENT_PARENT (element) != NULL))
|
|
||||||
goto had_parent;
|
|
||||||
|
|
||||||
elem_name = g_strdup (GST_ELEMENT_NAME (element));
|
|
||||||
GST_UNLOCK (element);
|
|
||||||
|
|
||||||
GST_LOCK (bin);
|
|
||||||
/* we obviously can't add ourself to ourself */
|
/* we obviously can't add ourself to ourself */
|
||||||
if (G_UNLIKELY (GST_ELEMENT_CAST (element) == GST_ELEMENT_CAST (bin)))
|
if (G_UNLIKELY (GST_ELEMENT_CAST (element) == GST_ELEMENT_CAST (bin)))
|
||||||
goto adding_itself;
|
goto adding_itself;
|
||||||
|
|
||||||
|
GST_LOCK (element);
|
||||||
|
elem_name = g_strdup (GST_ELEMENT_NAME (element));
|
||||||
|
GST_UNLOCK (element);
|
||||||
|
|
||||||
|
GST_LOCK (bin);
|
||||||
/* then check to see if the element's name is already taken in the bin,
|
/* then check to see if the element's name is already taken in the bin,
|
||||||
* we can safely take the lock here. We can leave the element locked
|
* we can safely take the lock here. This check is probably bogus because
|
||||||
* as it will not be in the bin. This check is probably bogus because
|
|
||||||
* you can safely change the element name after adding it to the bin. */
|
* you can safely change the element name after adding it to the bin. */
|
||||||
if (G_UNLIKELY (gst_object_check_uniqueness (bin->children,
|
if (G_UNLIKELY (gst_object_check_uniqueness (bin->children,
|
||||||
elem_name) == FALSE))
|
elem_name) == FALSE))
|
||||||
goto duplicate_name;
|
goto duplicate_name;
|
||||||
|
|
||||||
manager = GST_ELEMENT (bin)->manager;
|
|
||||||
gst_element_set_manager (element, manager);
|
|
||||||
|
|
||||||
/* set the element's parent and add the element to the bin's list of children */
|
/* 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_prepend (bin->children, element);
|
bin->children = g_list_prepend (bin->children, element);
|
||||||
bin->numchildren++;
|
bin->numchildren++;
|
||||||
bin->children_cookie++;
|
bin->children_cookie++;
|
||||||
|
|
||||||
|
manager = GST_ELEMENT (bin)->manager;
|
||||||
|
gst_element_set_manager (element, manager);
|
||||||
|
|
||||||
GST_UNLOCK (bin);
|
GST_UNLOCK (bin);
|
||||||
|
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, bin, "added element \"%s\"",
|
GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, bin, "added element \"%s\"",
|
||||||
|
@ -299,16 +297,10 @@ gst_bin_add_func (GstBin * bin, GstElement * element)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/* ERROR handling here */
|
/* ERROR handling here */
|
||||||
had_parent:
|
|
||||||
g_warning ("Element %s already has parent %p", GST_ELEMENT_NAME (element),
|
|
||||||
bin);
|
|
||||||
GST_UNLOCK (element);
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
adding_itself:
|
adding_itself:
|
||||||
|
GST_LOCK (bin);
|
||||||
g_warning ("Cannot add bin %s to itself", GST_ELEMENT_NAME (bin));
|
g_warning ("Cannot add bin %s to itself", GST_ELEMENT_NAME (bin));
|
||||||
GST_UNLOCK (bin);
|
GST_UNLOCK (bin);
|
||||||
g_free (elem_name);
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
duplicate_name:
|
duplicate_name:
|
||||||
|
@ -317,6 +309,12 @@ duplicate_name:
|
||||||
GST_UNLOCK (bin);
|
GST_UNLOCK (bin);
|
||||||
g_free (elem_name);
|
g_free (elem_name);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
had_parent:
|
||||||
|
g_warning ("Element %s already has parent", elem_name);
|
||||||
|
GST_UNLOCK (bin);
|
||||||
|
g_free (elem_name);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -364,18 +362,12 @@ gst_bin_remove_func (GstBin * bin, GstElement * element)
|
||||||
{
|
{
|
||||||
gchar *elem_name;
|
gchar *elem_name;
|
||||||
|
|
||||||
/* the element must have its parent set to the current bin */
|
|
||||||
GST_LOCK (element);
|
GST_LOCK (element);
|
||||||
/* the element must not already have a parent */
|
|
||||||
if (G_UNLIKELY (GST_ELEMENT_PARENT (element) != GST_ELEMENT_CAST (bin)))
|
|
||||||
goto wrong_parent;
|
|
||||||
|
|
||||||
elem_name = g_strdup (GST_ELEMENT_NAME (element));
|
elem_name = g_strdup (GST_ELEMENT_NAME (element));
|
||||||
GST_UNLOCK (element);
|
GST_UNLOCK (element);
|
||||||
|
|
||||||
GST_LOCK (bin);
|
GST_LOCK (bin);
|
||||||
/* the element must be in the bin's list of children, is this
|
/* the element must be in the bin's list of children */
|
||||||
* check redundant with PARENT checking? */
|
|
||||||
if (G_UNLIKELY (g_list_find (bin->children, element) == NULL))
|
if (G_UNLIKELY (g_list_find (bin->children, element) == NULL))
|
||||||
goto not_in_bin;
|
goto not_in_bin;
|
||||||
|
|
||||||
|
@ -391,18 +383,16 @@ gst_bin_remove_func (GstBin * bin, GstElement * element)
|
||||||
|
|
||||||
gst_element_set_manager (element, NULL);
|
gst_element_set_manager (element, NULL);
|
||||||
|
|
||||||
/* we should ref here to avoid bad app behaviour.. */
|
/* we ref here because after the _unparent() the element can be disposed
|
||||||
|
* and we still need it to fire a signal. */
|
||||||
|
gst_object_ref (GST_OBJECT (element));
|
||||||
gst_object_unparent (GST_OBJECT (element));
|
gst_object_unparent (GST_OBJECT (element));
|
||||||
|
|
||||||
g_signal_emit (G_OBJECT (bin), gst_bin_signals[ELEMENT_REMOVED], 0, element);
|
g_signal_emit (G_OBJECT (bin), gst_bin_signals[ELEMENT_REMOVED], 0, element);
|
||||||
|
gst_object_unref (GST_OBJECT (element));
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
wrong_parent:
|
|
||||||
g_warning ("Element %s is not in bin %p", GST_ELEMENT_NAME (element), bin);
|
|
||||||
GST_UNLOCK (element);
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
not_in_bin:
|
not_in_bin:
|
||||||
g_warning ("Element %s is not in bin %s", elem_name, GST_ELEMENT_NAME (bin));
|
g_warning ("Element %s is not in bin %s", elem_name, GST_ELEMENT_NAME (bin));
|
||||||
GST_UNLOCK (bin);
|
GST_UNLOCK (bin);
|
||||||
|
@ -454,43 +444,6 @@ no_function:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* bin iterator
|
|
||||||
*/
|
|
||||||
typedef struct _GstBinIterator
|
|
||||||
{
|
|
||||||
GstIterator iterator;
|
|
||||||
GstBin *bin;
|
|
||||||
GList *list; /* pointer in list */
|
|
||||||
} GstBinIterator;
|
|
||||||
|
|
||||||
static GstIteratorResult
|
|
||||||
gst_bin_iterator_next (GstBinIterator * it, GstElement ** elem)
|
|
||||||
{
|
|
||||||
if (it->list == NULL)
|
|
||||||
return GST_ITERATOR_DONE;
|
|
||||||
|
|
||||||
*elem = GST_ELEMENT (it->list->data);
|
|
||||||
gst_object_ref (GST_OBJECT (*elem));
|
|
||||||
|
|
||||||
it->list = g_list_next (it->list);
|
|
||||||
|
|
||||||
return GST_ITERATOR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_bin_iterator_resync (GstBinIterator * it)
|
|
||||||
{
|
|
||||||
it->list = it->bin->children;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_bin_iterator_free (GstBinIterator * it)
|
|
||||||
{
|
|
||||||
gst_object_unref (GST_OBJECT (it->bin));
|
|
||||||
g_free (it);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_bin_iterate_elements:
|
* gst_bin_iterate_elements:
|
||||||
* @bin: #Gstbin to iterate the elements of
|
* @bin: #Gstbin to iterate the elements of
|
||||||
|
@ -507,24 +460,22 @@ gst_bin_iterator_free (GstBinIterator * it)
|
||||||
GstIterator *
|
GstIterator *
|
||||||
gst_bin_iterate_elements (GstBin * bin)
|
gst_bin_iterate_elements (GstBin * bin)
|
||||||
{
|
{
|
||||||
GstBinIterator *result;
|
GstIterator *result;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
|
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
|
||||||
|
|
||||||
/* ne need to lock, nothing can change here */
|
|
||||||
result = (GstBinIterator *) gst_iterator_new (sizeof (GstBinIterator),
|
|
||||||
GST_GET_LOCK (bin),
|
|
||||||
&bin->children_cookie,
|
|
||||||
(GstIteratorNextFunction) gst_bin_iterator_next,
|
|
||||||
(GstIteratorResyncFunction) gst_bin_iterator_resync,
|
|
||||||
(GstIteratorFreeFunction) gst_bin_iterator_free);
|
|
||||||
|
|
||||||
GST_LOCK (bin);
|
GST_LOCK (bin);
|
||||||
result->bin = GST_BIN (gst_object_ref (GST_OBJECT (bin)));
|
gst_object_ref (GST_OBJECT (bin));
|
||||||
result->list = bin->children;
|
result = gst_iterator_new_list (GST_GET_LOCK (bin),
|
||||||
|
&bin->children_cookie,
|
||||||
|
&bin->children,
|
||||||
|
bin,
|
||||||
|
(GstIteratorRefFunction) gst_object_ref,
|
||||||
|
(GstIteratorUnrefFunction) gst_object_unref,
|
||||||
|
(GstIteratorDisposeFunction) gst_object_unref);
|
||||||
GST_UNLOCK (bin);
|
GST_UNLOCK (bin);
|
||||||
|
|
||||||
return GST_ITERATOR (result);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns 0 if the element is a sink, this is made so that
|
/* returns 0 if the element is a sink, this is made so that
|
||||||
|
@ -735,22 +686,22 @@ gst_bin_change_state (GstElement * element)
|
||||||
/* FIXME does not work for bins etc */
|
/* FIXME does not work for bins etc */
|
||||||
peer_elem = GST_ELEMENT (gst_object_get_parent (GST_OBJECT (peer)));
|
peer_elem = GST_ELEMENT (gst_object_get_parent (GST_OBJECT (peer)));
|
||||||
|
|
||||||
|
if (peer_elem) {
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
|
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
|
||||||
"adding element %s to queue", gst_element_get_name (peer_elem));
|
"adding element %s to queue", gst_element_get_name (peer_elem));
|
||||||
|
|
||||||
/* ref before pushing on the queue */
|
/* is reffed before pushing on the queue */
|
||||||
gst_object_ref (GST_OBJECT (peer_elem));
|
|
||||||
g_queue_push_tail (elem_queue, peer_elem);
|
g_queue_push_tail (elem_queue, peer_elem);
|
||||||
|
}
|
||||||
|
gst_object_unref (GST_OBJECT (peer));
|
||||||
} else {
|
} else {
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
|
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
|
||||||
"pad %s:%s does not have a peer", GST_DEBUG_PAD_NAME (pad));
|
"pad %s:%s does not have a peer", GST_DEBUG_PAD_NAME (pad));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GST_FLAG_IS_SET (qelement, GST_ELEMENT_LOCKED_STATE)) {
|
if (GST_FLAG_IS_SET (qelement, GST_ELEMENT_LOCKED_STATE))
|
||||||
gst_object_unref (GST_OBJECT (qelement));
|
goto next_element;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FIXME handle delayed elements like src and loop based
|
/* FIXME handle delayed elements like src and loop based
|
||||||
* elements */
|
* elements */
|
||||||
|
@ -774,8 +725,6 @@ gst_bin_change_state (GstElement * element)
|
||||||
GST_ELEMENT_NAME (qelement),
|
GST_ELEMENT_NAME (qelement),
|
||||||
pending, gst_element_state_get_name (pending));
|
pending, gst_element_state_get_name (pending));
|
||||||
ret = GST_STATE_FAILURE;
|
ret = GST_STATE_FAILURE;
|
||||||
/* release refcounts in queue */
|
|
||||||
g_queue_foreach (elem_queue, (GFunc) gst_object_unref, NULL);
|
|
||||||
/* release refcount of element we popped off the queue */
|
/* release refcount of element we popped off the queue */
|
||||||
gst_object_unref (GST_OBJECT (qelement));
|
gst_object_unref (GST_OBJECT (qelement));
|
||||||
goto exit;
|
goto exit;
|
||||||
|
@ -783,6 +732,7 @@ gst_bin_change_state (GstElement * element)
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
next_element:
|
||||||
gst_object_unref (GST_OBJECT (qelement));
|
gst_object_unref (GST_OBJECT (qelement));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -807,6 +757,8 @@ gst_bin_change_state (GstElement * element)
|
||||||
gst_element_state_get_name (GST_STATE (element)));
|
gst_element_state_get_name (GST_STATE (element)));
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
|
/* release refcounts in queue, should normally be empty */
|
||||||
|
g_queue_foreach (elem_queue, (GFunc) gst_object_unref, NULL);
|
||||||
g_queue_free (elem_queue);
|
g_queue_free (elem_queue);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -820,6 +772,8 @@ gst_bin_dispose (GObject * object)
|
||||||
|
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, object, "dispose");
|
GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, object, "dispose");
|
||||||
|
|
||||||
|
/* ref to not hit 0 again */
|
||||||
|
gst_object_ref (GST_OBJECT (object));
|
||||||
gst_element_set_state (GST_ELEMENT (object), GST_STATE_NULL);
|
gst_element_set_state (GST_ELEMENT (object), GST_STATE_NULL);
|
||||||
|
|
||||||
while (bin->children) {
|
while (bin->children) {
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
#include "gst_private.h"
|
#include "gst_private.h"
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
|
||||||
#define DEBUG_REFCOUNT
|
//#define DEBUG_REFCOUNT
|
||||||
|
|
||||||
#define CAPS_POISON(caps) G_STMT_START{ \
|
#define CAPS_POISON(caps) G_STMT_START{ \
|
||||||
if (caps) { \
|
if (caps) { \
|
||||||
|
|
388
gst/gstelement.c
388
gst/gstelement.c
|
@ -1,6 +1,6 @@
|
||||||
/* GStreamer
|
/* GStreamer
|
||||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||||
* 2000 Wim Taymans <wtay@chello.be>
|
* 2004 Wim Taymans <wim@fluendo.com>
|
||||||
*
|
*
|
||||||
* gstelement.c: The base element, all elements derive from this
|
* gstelement.c: The base element, all elements derive from this
|
||||||
*
|
*
|
||||||
|
@ -441,6 +441,7 @@ gst_element_add_pad (GstElement * element, GstPad * pad)
|
||||||
goto had_parent;
|
goto had_parent;
|
||||||
|
|
||||||
GST_LOCK (element);
|
GST_LOCK (element);
|
||||||
|
/* locking pad to look at the name */
|
||||||
GST_LOCK (pad);
|
GST_LOCK (pad);
|
||||||
/* then check to see if there's already a pad by that name here */
|
/* then check to see if there's already a pad by that name here */
|
||||||
if (G_UNLIKELY (!gst_object_check_uniqueness (element->pads,
|
if (G_UNLIKELY (!gst_object_check_uniqueness (element->pads,
|
||||||
|
@ -551,20 +552,25 @@ gst_element_add_ghost_pad (GstElement * element, GstPad * pad,
|
||||||
* Removes @pad from @element. @pad will be destroyed if it has not been
|
* Removes @pad from @element. @pad will be destroyed if it has not been
|
||||||
* referenced elsewhere.
|
* referenced elsewhere.
|
||||||
*
|
*
|
||||||
|
* Returns: TRUE if the pad could be removed. Can return FALSE if the
|
||||||
|
* pad is not belonging to the provided element or when wrong parameters
|
||||||
|
* are passed to this function.
|
||||||
|
*
|
||||||
* MT safe.
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
void
|
gboolean
|
||||||
gst_element_remove_pad (GstElement * element, GstPad * pad)
|
gst_element_remove_pad (GstElement * element, GstPad * pad)
|
||||||
{
|
{
|
||||||
GstElement *current_parent;
|
GstElement *current_parent;
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_ELEMENT (element));
|
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
|
||||||
g_return_if_fail (GST_IS_PAD (pad));
|
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
|
||||||
|
|
||||||
current_parent = gst_pad_get_parent (pad);
|
current_parent = gst_pad_get_parent (pad);
|
||||||
if (G_UNLIKELY (current_parent != element))
|
if (G_UNLIKELY (current_parent != element))
|
||||||
goto not_our_pad;
|
goto not_our_pad;
|
||||||
|
|
||||||
|
/* FIXME, is this redundant with pad disposal? */
|
||||||
if (GST_IS_REAL_PAD (pad)) {
|
if (GST_IS_REAL_PAD (pad)) {
|
||||||
GstPad *peer = gst_pad_get_peer (pad);
|
GstPad *peer = gst_pad_get_peer (pad);
|
||||||
|
|
||||||
|
@ -573,7 +579,10 @@ gst_element_remove_pad (GstElement * element, GstPad * pad)
|
||||||
/* window for MT unsafeness, someone else could unlink here
|
/* window for MT unsafeness, someone else could unlink here
|
||||||
* and then we call unlink with wrong pads. The unlink
|
* and then we call unlink with wrong pads. The unlink
|
||||||
* function would catch this and safely return failed. */
|
* function would catch this and safely return failed. */
|
||||||
|
if (GST_PAD_IS_SRC (pad))
|
||||||
gst_pad_unlink (pad, GST_PAD_CAST (peer));
|
gst_pad_unlink (pad, GST_PAD_CAST (peer));
|
||||||
|
else
|
||||||
|
gst_pad_unlink (GST_PAD_CAST (peer), pad);
|
||||||
gst_object_unref (GST_OBJECT (peer));
|
gst_object_unref (GST_OBJECT (peer));
|
||||||
}
|
}
|
||||||
} else if (GST_IS_GHOST_PAD (pad)) {
|
} else if (GST_IS_GHOST_PAD (pad)) {
|
||||||
|
@ -604,7 +613,7 @@ gst_element_remove_pad (GstElement * element, GstPad * pad)
|
||||||
|
|
||||||
gst_object_unparent (GST_OBJECT (pad));
|
gst_object_unparent (GST_OBJECT (pad));
|
||||||
|
|
||||||
return;
|
return TRUE;
|
||||||
|
|
||||||
not_our_pad:
|
not_our_pad:
|
||||||
{
|
{
|
||||||
|
@ -618,7 +627,7 @@ not_our_pad:
|
||||||
GST_UNLOCK (element);
|
GST_UNLOCK (element);
|
||||||
GST_UNLOCK (pad);
|
GST_UNLOCK (pad);
|
||||||
g_free (parent_name);
|
g_free (parent_name);
|
||||||
return;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -642,36 +651,16 @@ gst_element_no_more_pads (GstElement * element)
|
||||||
g_signal_emit (element, gst_element_signals[NO_MORE_PADS], 0);
|
g_signal_emit (element, gst_element_signals[NO_MORE_PADS], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_element_get_pad:
|
|
||||||
* @element: a #GstElement.
|
|
||||||
* @name: the name of the pad to retrieve.
|
|
||||||
*
|
|
||||||
* Retrieves a pad from @element by name. Tries gst_element_get_static_pad()
|
|
||||||
* first, then gst_element_get_request_pad().
|
|
||||||
*
|
|
||||||
* Returns: the #GstPad if found, otherwise %NULL.
|
|
||||||
*/
|
|
||||||
GstPad *
|
|
||||||
gst_element_get_pad (GstElement * element, const gchar * name)
|
|
||||||
{
|
|
||||||
GstPad *pad;
|
|
||||||
|
|
||||||
g_return_val_if_fail (element != NULL, NULL);
|
|
||||||
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
|
||||||
g_return_val_if_fail (name != NULL, NULL);
|
|
||||||
|
|
||||||
pad = gst_element_get_static_pad (element, name);
|
|
||||||
if (!pad)
|
|
||||||
pad = gst_element_get_request_pad (element, name);
|
|
||||||
|
|
||||||
return pad;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gint
|
static gint
|
||||||
pad_compare_name (GstPad * pad1, const gchar * name)
|
pad_compare_name (GstPad * pad1, const gchar * name)
|
||||||
{
|
{
|
||||||
return strcmp (GST_PAD_NAME (pad1), name);
|
gint result;
|
||||||
|
|
||||||
|
GST_LOCK (pad1);
|
||||||
|
result = strcmp (GST_PAD_NAME (pad1), name);
|
||||||
|
GST_UNLOCK (pad1);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -682,7 +671,10 @@ pad_compare_name (GstPad * pad1, const gchar * name)
|
||||||
* Retrieves a pad from @element by name. This version only retrieves
|
* Retrieves a pad from @element by name. This version only retrieves
|
||||||
* already-existing (i.e. 'static') pads.
|
* already-existing (i.e. 'static') pads.
|
||||||
*
|
*
|
||||||
* Returns: the requested #GstPad if found, otherwise NULL.
|
* Returns: the requested #GstPad if found, otherwise NULL. unref after
|
||||||
|
* usage.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstPad *
|
GstPad *
|
||||||
gst_element_get_static_pad (GstElement * element, const gchar * name)
|
gst_element_get_static_pad (GstElement * element, const gchar * name)
|
||||||
|
@ -690,24 +682,26 @@ gst_element_get_static_pad (GstElement * element, const gchar * name)
|
||||||
GList *find;
|
GList *find;
|
||||||
GstPad *result = NULL;
|
GstPad *result = NULL;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_ELEMENT (element), result);
|
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
||||||
g_return_val_if_fail (name != NULL, result);
|
g_return_val_if_fail (name != NULL, NULL);
|
||||||
|
|
||||||
GST_LOCK (element);
|
GST_LOCK (element);
|
||||||
find =
|
find =
|
||||||
g_list_find_custom (element->pads, name, (GCompareFunc) pad_compare_name);
|
g_list_find_custom (element->pads, name, (GCompareFunc) pad_compare_name);
|
||||||
if (find) {
|
if (find) {
|
||||||
result = GST_PAD (find->data);
|
result = GST_PAD (find->data);
|
||||||
|
gst_object_ref (GST_OBJECT (result));
|
||||||
}
|
}
|
||||||
GST_UNLOCK (element);
|
|
||||||
|
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "no such pad '%s' in element \"%s\"",
|
GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "no such pad '%s' in element \"%s\"",
|
||||||
name, GST_OBJECT_NAME (element));
|
name, GST_ELEMENT_NAME (element));
|
||||||
} else {
|
} else {
|
||||||
GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "found pad %s:%s",
|
GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "found pad %s:%s",
|
||||||
GST_DEBUG_PAD_NAME (result));
|
GST_ELEMENT_NAME (element), name);
|
||||||
}
|
}
|
||||||
|
GST_UNLOCK (element);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -749,7 +743,6 @@ gst_element_get_request_pad (GstElement * element, const gchar * name)
|
||||||
gchar *str, *endptr = NULL;
|
gchar *str, *endptr = NULL;
|
||||||
GstElementClass *class;
|
GstElementClass *class;
|
||||||
|
|
||||||
g_return_val_if_fail (element != NULL, NULL);
|
|
||||||
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
||||||
g_return_val_if_fail (name != NULL, NULL);
|
g_return_val_if_fail (name != NULL, NULL);
|
||||||
|
|
||||||
|
@ -804,30 +797,60 @@ gst_element_get_request_pad (GstElement * element, const gchar * name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_element_get_pad_list:
|
* gst_element_get_pad:
|
||||||
* @element: a #GstElement to get pads of.
|
* @element: a #GstElement.
|
||||||
|
* @name: the name of the pad to retrieve.
|
||||||
*
|
*
|
||||||
* Retrieves a list of @element's pads. The list must not be modified by the
|
* Retrieves a pad from @element by name. Tries gst_element_get_static_pad()
|
||||||
* calling code.
|
* first, then gst_element_get_request_pad().
|
||||||
*
|
*
|
||||||
* Returns: the #GList of pads.
|
* Returns: the #GstPad if found, otherwise %NULL. Unref after usage.
|
||||||
*/
|
*/
|
||||||
const GList *
|
GstPad *
|
||||||
gst_element_get_pad_list (GstElement * element)
|
gst_element_get_pad (GstElement * element, const gchar * name)
|
||||||
{
|
{
|
||||||
const GList *result = NULL;
|
GstPad *pad;
|
||||||
|
|
||||||
g_return_val_if_fail (element != NULL, result);
|
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
||||||
g_return_val_if_fail (GST_IS_ELEMENT (element), result);
|
g_return_val_if_fail (name != NULL, NULL);
|
||||||
|
|
||||||
g_warning ("calling gst_element_get_pad_list is MT unsafe!!");
|
pad = gst_element_get_static_pad (element, name);
|
||||||
|
if (!pad)
|
||||||
|
pad = gst_element_get_request_pad (element, name);
|
||||||
|
|
||||||
/* return the list of pads */
|
return pad;
|
||||||
result = element->pads;
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_element_iterate_pads:
|
||||||
|
* @element: a #GstElement to iterate pads of.
|
||||||
|
*
|
||||||
|
* Retrieves an iterattor of @element's pads.
|
||||||
|
*
|
||||||
|
* Returns: the #GstIterator of pads.
|
||||||
|
*/
|
||||||
|
GstIterator *
|
||||||
|
gst_element_iterate_pads (GstElement * element)
|
||||||
|
{
|
||||||
|
GstIterator *result;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
||||||
|
|
||||||
|
GST_LOCK (element);
|
||||||
|
gst_object_ref (GST_OBJECT (element));
|
||||||
|
result = gst_iterator_new_list (GST_GET_LOCK (element),
|
||||||
|
&element->pads_cookie,
|
||||||
|
&element->pads,
|
||||||
|
element,
|
||||||
|
(GstIteratorRefFunction) gst_object_ref,
|
||||||
|
(GstIteratorUnrefFunction) gst_object_unref,
|
||||||
|
(GstIteratorDisposeFunction) gst_object_unref);
|
||||||
|
GST_UNLOCK (element);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_element_class_add_pad_template:
|
* gst_element_class_add_pad_template:
|
||||||
* @klass: the #GstElementClass to add the pad template to.
|
* @klass: the #GstElementClass to add the pad template to.
|
||||||
|
@ -885,7 +908,6 @@ gst_element_class_set_details (GstElementClass * klass,
|
||||||
GList *
|
GList *
|
||||||
gst_element_class_get_pad_template_list (GstElementClass * element_class)
|
gst_element_class_get_pad_template_list (GstElementClass * element_class)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (element_class != NULL, NULL);
|
|
||||||
g_return_val_if_fail (GST_IS_ELEMENT_CLASS (element_class), NULL);
|
g_return_val_if_fail (GST_IS_ELEMENT_CLASS (element_class), NULL);
|
||||||
|
|
||||||
return element_class->padtemplates;
|
return element_class->padtemplates;
|
||||||
|
@ -910,7 +932,6 @@ gst_element_class_get_pad_template (GstElementClass * element_class,
|
||||||
{
|
{
|
||||||
GList *padlist;
|
GList *padlist;
|
||||||
|
|
||||||
g_return_val_if_fail (element_class != NULL, NULL);
|
|
||||||
g_return_val_if_fail (GST_IS_ELEMENT_CLASS (element_class), NULL);
|
g_return_val_if_fail (GST_IS_ELEMENT_CLASS (element_class), NULL);
|
||||||
g_return_val_if_fail (name != NULL, NULL);
|
g_return_val_if_fail (name != NULL, NULL);
|
||||||
|
|
||||||
|
@ -949,17 +970,23 @@ gst_element_get_random_pad (GstElement * element, GstPadDirection dir)
|
||||||
for (; pads; pads = g_list_next (pads)) {
|
for (; pads; pads = g_list_next (pads)) {
|
||||||
GstPad *pad = GST_PAD (pads->data);
|
GstPad *pad = GST_PAD (pads->data);
|
||||||
|
|
||||||
|
GST_LOCK (pad);
|
||||||
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "checking pad %s:%s",
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "checking pad %s:%s",
|
||||||
GST_DEBUG_PAD_NAME (pad));
|
GST_DEBUG_PAD_NAME (pad));
|
||||||
|
|
||||||
if (GST_PAD_IS_LINKED (pad)) {
|
if (GST_PAD_IS_LINKED (pad)) {
|
||||||
|
GST_UNLOCK (pad);
|
||||||
result = pad;
|
result = pad;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is not linked",
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is not linked",
|
||||||
GST_DEBUG_PAD_NAME (pad));
|
GST_DEBUG_PAD_NAME (pad));
|
||||||
}
|
}
|
||||||
|
GST_UNLOCK (pad);
|
||||||
}
|
}
|
||||||
|
if (result)
|
||||||
|
gst_object_ref (GST_OBJECT (result));
|
||||||
|
|
||||||
GST_UNLOCK (element);
|
GST_UNLOCK (element);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -973,27 +1000,38 @@ gst_element_get_random_pad (GstElement * element, GstPadDirection dir)
|
||||||
* If the element doesn't implement an event masks function,
|
* If the element doesn't implement an event masks function,
|
||||||
* the query will be forwarded to a random linked sink pad.
|
* the query will be forwarded to a random linked sink pad.
|
||||||
*
|
*
|
||||||
* Returns: An array of #GstEventMask elements.
|
* Returns: An array of #GstEventMask elements. The array
|
||||||
|
* cannot be modified or freed.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
const GstEventMask *
|
const GstEventMask *
|
||||||
gst_element_get_event_masks (GstElement * element)
|
gst_element_get_event_masks (GstElement * element)
|
||||||
{
|
{
|
||||||
GstElementClass *oclass;
|
GstElementClass *oclass;
|
||||||
|
const GstEventMask *result = NULL;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
||||||
|
|
||||||
oclass = GST_ELEMENT_GET_CLASS (element);
|
oclass = GST_ELEMENT_GET_CLASS (element);
|
||||||
|
|
||||||
if (oclass->get_event_masks)
|
if (oclass->get_event_masks) {
|
||||||
return oclass->get_event_masks (element);
|
result = oclass->get_event_masks (element);
|
||||||
else {
|
} else {
|
||||||
GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
|
GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
|
||||||
|
|
||||||
if (pad)
|
if (pad) {
|
||||||
return gst_pad_get_event_masks (GST_PAD_PEER (pad));
|
GstPad *peer = gst_pad_get_peer (pad);
|
||||||
|
|
||||||
|
if (peer) {
|
||||||
|
result = gst_pad_get_event_masks (peer);
|
||||||
|
gst_object_unref (GST_OBJECT (peer));
|
||||||
|
}
|
||||||
|
gst_object_unref (GST_OBJECT (pad));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1003,34 +1041,47 @@ gst_element_get_event_masks (GstElement * element)
|
||||||
*
|
*
|
||||||
* Sends an event to an element. If the element doesn't
|
* Sends an event to an element. If the element doesn't
|
||||||
* implement an event handler, the event will be forwarded
|
* implement an event handler, the event will be forwarded
|
||||||
* to a random sink pad.
|
* to a random sink pad. This function takes owership of the
|
||||||
|
* provided event so you should _ref it if you want to reuse
|
||||||
|
* the event after this call.
|
||||||
*
|
*
|
||||||
* Returns: TRUE if the event was handled.
|
* Returns: TRUE if the event was handled.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
gst_element_send_event (GstElement * element, GstEvent * event)
|
gst_element_send_event (GstElement * element, GstEvent * event)
|
||||||
{
|
{
|
||||||
GstElementClass *oclass;
|
GstElementClass *oclass;
|
||||||
|
gboolean result = FALSE;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
|
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
|
||||||
g_return_val_if_fail (event != NULL, FALSE);
|
g_return_val_if_fail (event != NULL, FALSE);
|
||||||
|
|
||||||
oclass = GST_ELEMENT_GET_CLASS (element);
|
oclass = GST_ELEMENT_GET_CLASS (element);
|
||||||
|
|
||||||
if (oclass->send_event)
|
if (oclass->send_event) {
|
||||||
return oclass->send_event (element, event);
|
result = oclass->send_event (element, event);
|
||||||
else {
|
} else {
|
||||||
GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
|
GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
|
||||||
|
|
||||||
if (pad) {
|
if (pad) {
|
||||||
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "sending event to random pad %s:%s",
|
GstPad *peer = gst_pad_get_peer (pad);
|
||||||
GST_DEBUG_PAD_NAME (pad));
|
|
||||||
return gst_pad_send_event (GST_PAD_PEER (pad), event);
|
if (peer) {
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
||||||
|
"sending event to random pad %s:%s", GST_DEBUG_PAD_NAME (pad));
|
||||||
|
|
||||||
|
result = gst_pad_send_event (peer, event);
|
||||||
|
gst_object_unref (GST_OBJECT (peer));
|
||||||
|
}
|
||||||
|
gst_object_unref (GST_OBJECT (pad));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "can't send event on element %s",
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "can't send event on element %s",
|
||||||
GST_ELEMENT_NAME (element));
|
GST_ELEMENT_NAME (element));
|
||||||
return FALSE;
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1042,13 +1093,18 @@ gst_element_send_event (GstElement * element, GstEvent * event)
|
||||||
* Sends a seek event to an element.
|
* Sends a seek event to an element.
|
||||||
*
|
*
|
||||||
* Returns: TRUE if the event was handled.
|
* Returns: TRUE if the event was handled.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
gst_element_seek (GstElement * element, GstSeekType seek_type, guint64 offset)
|
gst_element_seek (GstElement * element, GstSeekType seek_type, guint64 offset)
|
||||||
{
|
{
|
||||||
GstEvent *event = gst_event_new_seek (seek_type, offset);
|
GstEvent *event = gst_event_new_seek (seek_type, offset);
|
||||||
|
gboolean result;
|
||||||
|
|
||||||
return gst_element_send_event (element, event);
|
result = gst_element_send_event (element, event);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1059,27 +1115,38 @@ gst_element_seek (GstElement * element, GstSeekType seek_type, guint64 offset)
|
||||||
* If the element doesn't implement a query types function,
|
* If the element doesn't implement a query types function,
|
||||||
* the query will be forwarded to a random sink pad.
|
* the query will be forwarded to a random sink pad.
|
||||||
*
|
*
|
||||||
* Returns: An array of #GstQueryType elements.
|
* Returns: An array of #GstQueryType elements that should not
|
||||||
|
* be freed or modified.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
const GstQueryType *
|
const GstQueryType *
|
||||||
gst_element_get_query_types (GstElement * element)
|
gst_element_get_query_types (GstElement * element)
|
||||||
{
|
{
|
||||||
GstElementClass *oclass;
|
GstElementClass *oclass;
|
||||||
|
const GstQueryType *result = NULL;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
||||||
|
|
||||||
oclass = GST_ELEMENT_GET_CLASS (element);
|
oclass = GST_ELEMENT_GET_CLASS (element);
|
||||||
|
|
||||||
if (oclass->get_query_types)
|
if (oclass->get_query_types) {
|
||||||
return oclass->get_query_types (element);
|
result = oclass->get_query_types (element);
|
||||||
else {
|
} else {
|
||||||
GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
|
GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
|
||||||
|
|
||||||
if (pad)
|
if (pad) {
|
||||||
return gst_pad_get_query_types (GST_PAD_PEER (pad));
|
GstPad *peer = gst_pad_get_peer (pad);
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
if (peer) {
|
||||||
|
result = gst_pad_get_query_types (peer);
|
||||||
|
|
||||||
|
gst_object_unref (GST_OBJECT (peer));
|
||||||
|
}
|
||||||
|
gst_object_unref (GST_OBJECT (pad));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1102,6 +1169,7 @@ gst_element_query (GstElement * element, GstQueryType type,
|
||||||
GstFormat * format, gint64 * value)
|
GstFormat * format, gint64 * value)
|
||||||
{
|
{
|
||||||
GstElementClass *oclass;
|
GstElementClass *oclass;
|
||||||
|
gboolean result = FALSE;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
|
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
|
||||||
g_return_val_if_fail (format != NULL, FALSE);
|
g_return_val_if_fail (format != NULL, FALSE);
|
||||||
|
@ -1109,19 +1177,30 @@ gst_element_query (GstElement * element, GstQueryType type,
|
||||||
|
|
||||||
oclass = GST_ELEMENT_GET_CLASS (element);
|
oclass = GST_ELEMENT_GET_CLASS (element);
|
||||||
|
|
||||||
if (oclass->query)
|
if (oclass->query) {
|
||||||
return oclass->query (element, type, format, value);
|
result = oclass->query (element, type, format, value);
|
||||||
else {
|
} else {
|
||||||
GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SRC);
|
GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SRC);
|
||||||
|
|
||||||
if (pad)
|
if (pad) {
|
||||||
return gst_pad_query (pad, type, format, value);
|
result = gst_pad_query (pad, type, format, value);
|
||||||
pad = gst_element_get_random_pad (element, GST_PAD_SINK);
|
|
||||||
if (pad)
|
|
||||||
return gst_pad_query (GST_PAD_PEER (pad), type, format, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
gst_object_unref (GST_OBJECT (pad));
|
||||||
|
} else {
|
||||||
|
pad = gst_element_get_random_pad (element, GST_PAD_SINK);
|
||||||
|
if (pad) {
|
||||||
|
GstPad *peer = gst_pad_get_peer (pad);
|
||||||
|
|
||||||
|
if (peer) {
|
||||||
|
result = gst_pad_query (peer, type, format, value);
|
||||||
|
|
||||||
|
gst_object_unref (GST_OBJECT (peer));
|
||||||
|
}
|
||||||
|
gst_object_unref (GST_OBJECT (pad));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1138,21 +1217,30 @@ const GstFormat *
|
||||||
gst_element_get_formats (GstElement * element)
|
gst_element_get_formats (GstElement * element)
|
||||||
{
|
{
|
||||||
GstElementClass *oclass;
|
GstElementClass *oclass;
|
||||||
|
const GstFormat *result = NULL;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
||||||
|
|
||||||
oclass = GST_ELEMENT_GET_CLASS (element);
|
oclass = GST_ELEMENT_GET_CLASS (element);
|
||||||
|
|
||||||
if (oclass->get_formats)
|
if (oclass->get_formats) {
|
||||||
return oclass->get_formats (element);
|
result = oclass->get_formats (element);
|
||||||
else {
|
} else {
|
||||||
GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
|
GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
|
||||||
|
|
||||||
if (pad)
|
if (pad) {
|
||||||
return gst_pad_get_formats (GST_PAD_PEER (pad));
|
GstPad *peer = gst_pad_get_peer (pad);
|
||||||
|
|
||||||
|
if (peer) {
|
||||||
|
result = gst_pad_get_formats (peer);
|
||||||
|
|
||||||
|
gst_object_unref (GST_OBJECT (peer));
|
||||||
|
}
|
||||||
|
gst_object_unref (GST_OBJECT (pad));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1175,6 +1263,7 @@ gst_element_convert (GstElement * element,
|
||||||
GstFormat * dest_format, gint64 * dest_value)
|
GstFormat * dest_format, gint64 * dest_value)
|
||||||
{
|
{
|
||||||
GstElementClass *oclass;
|
GstElementClass *oclass;
|
||||||
|
gboolean result = FALSE;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
|
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
|
||||||
g_return_val_if_fail (dest_format != NULL, FALSE);
|
g_return_val_if_fail (dest_format != NULL, FALSE);
|
||||||
|
@ -1187,36 +1276,53 @@ gst_element_convert (GstElement * element,
|
||||||
|
|
||||||
oclass = GST_ELEMENT_GET_CLASS (element);
|
oclass = GST_ELEMENT_GET_CLASS (element);
|
||||||
|
|
||||||
if (oclass->convert)
|
if (oclass->convert) {
|
||||||
return oclass->convert (element,
|
result = oclass->convert (element,
|
||||||
src_format, src_value, dest_format, dest_value);
|
src_format, src_value, dest_format, dest_value);
|
||||||
else {
|
} else {
|
||||||
GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
|
GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
|
||||||
|
|
||||||
if (pad)
|
if (pad) {
|
||||||
return gst_pad_convert (GST_PAD_PEER (pad),
|
GstPad *peer = gst_pad_get_peer (pad);
|
||||||
src_format, src_value, dest_format, dest_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
if (peer) {
|
||||||
|
result = gst_pad_convert (peer,
|
||||||
|
src_format, src_value, dest_format, dest_value);
|
||||||
|
|
||||||
|
gst_object_unref (GST_OBJECT (peer));
|
||||||
|
}
|
||||||
|
gst_object_unref (GST_OBJECT (pad));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MT safe */
|
/**
|
||||||
|
* gst_element_post_message:
|
||||||
|
* @element: a #GstElement posting the message
|
||||||
|
* @message: a #GstMessage to post
|
||||||
|
*
|
||||||
|
* Post a message on the elements #GstBus.
|
||||||
|
*
|
||||||
|
* Returns: TRUE if the message was successfuly posted.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
gst_element_post_message (GstElement * element, GstMessage * message)
|
gst_element_post_message (GstElement * element, GstMessage * message)
|
||||||
{
|
{
|
||||||
GstPipeline *manager;
|
GstPipeline *manager;
|
||||||
gboolean result = FALSE;
|
gboolean result = FALSE;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_ELEMENT (element), result);
|
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
|
||||||
g_return_val_if_fail (message != NULL, result);
|
g_return_val_if_fail (message != NULL, FALSE);
|
||||||
|
|
||||||
GST_LOCK (element);
|
GST_LOCK (element);
|
||||||
manager = element->manager;
|
manager = element->manager;
|
||||||
if (manager == NULL) {
|
if (manager == NULL) {
|
||||||
GST_UNLOCK (element);
|
GST_UNLOCK (element);
|
||||||
gst_data_unref (GST_DATA (message));
|
gst_data_unref (GST_DATA (message));
|
||||||
return result;
|
return FALSE;
|
||||||
}
|
}
|
||||||
gst_object_ref (GST_OBJECT (manager));
|
gst_object_ref (GST_OBJECT (manager));
|
||||||
GST_UNLOCK (element);
|
GST_UNLOCK (element);
|
||||||
|
@ -1234,6 +1340,8 @@ gst_element_post_message (GstElement * element, GstMessage * message)
|
||||||
* This function is only used internally by the #gst_element_error macro.
|
* This function is only used internally by the #gst_element_error macro.
|
||||||
*
|
*
|
||||||
* Returns: a newly allocated string, or NULL if the format was NULL or ""
|
* Returns: a newly allocated string, or NULL if the format was NULL or ""
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
gchar *
|
gchar *
|
||||||
_gst_element_error_printf (const gchar * format, ...)
|
_gst_element_error_printf (const gchar * format, ...)
|
||||||
|
@ -1268,6 +1376,8 @@ _gst_element_error_printf (const gchar * format, ...)
|
||||||
* Signals an error condition on an element.
|
* Signals an error condition on an element.
|
||||||
* This function is used internally by elements.
|
* This function is used internally by elements.
|
||||||
* It results in the "error" signal.
|
* It results in the "error" signal.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
void gst_element_error_full
|
void gst_element_error_full
|
||||||
(GstElement * element, GQuark domain, gint code, gchar * message,
|
(GstElement * element, GQuark domain, gint code, gchar * message,
|
||||||
|
@ -1363,6 +1473,8 @@ gst_element_is_locked_state (GstElement * element)
|
||||||
*
|
*
|
||||||
* Returns: TRUE if the state was changed, FALSE if bad params were given or
|
* Returns: TRUE if the state was changed, FALSE if bad params were given or
|
||||||
* the element was already in the correct state.
|
* the element was already in the correct state.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
gst_element_set_locked_state (GstElement * element, gboolean locked_state)
|
gst_element_set_locked_state (GstElement * element, gboolean locked_state)
|
||||||
|
@ -1386,6 +1498,8 @@ gst_element_set_locked_state (GstElement * element, gboolean locked_state)
|
||||||
GST_ELEMENT_NAME (element));
|
GST_ELEMENT_NAME (element));
|
||||||
GST_FLAG_UNSET (element, GST_ELEMENT_LOCKED_STATE);
|
GST_FLAG_UNSET (element, GST_ELEMENT_LOCKED_STATE);
|
||||||
}
|
}
|
||||||
|
GST_UNLOCK (element);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
was_ok:
|
was_ok:
|
||||||
|
@ -1423,6 +1537,7 @@ gst_element_sync_state_with_parent (GstElement * element)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* MT safe */
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_element_get_state_func (GstElement * element,
|
gst_element_get_state_func (GstElement * element,
|
||||||
GstElementState * state, GstElementState * pending, GTimeVal * timeout)
|
GstElementState * state, GstElementState * pending, GTimeVal * timeout)
|
||||||
|
@ -1461,7 +1576,6 @@ gst_element_get_state_func (GstElement * element,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_element_get_state:
|
* gst_element_get_state:
|
||||||
* @element: a #GstElement to get the state of.
|
* @element: a #GstElement to get the state of.
|
||||||
|
@ -1475,21 +1589,24 @@ gst_element_get_state_func (GstElement * element,
|
||||||
*
|
*
|
||||||
* Returns: TRUE if the element has no more pending state, FALSE
|
* Returns: TRUE if the element has no more pending state, FALSE
|
||||||
* if the element is still performing a state change.
|
* if the element is still performing a state change.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
gst_element_get_state (GstElement * element,
|
gst_element_get_state (GstElement * element,
|
||||||
GstElementState * state, GstElementState * pending, GTimeVal * timeout)
|
GstElementState * state, GstElementState * pending, GTimeVal * timeout)
|
||||||
{
|
{
|
||||||
GstElementClass *oclass;
|
GstElementClass *oclass;
|
||||||
|
gboolean result = FALSE;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
|
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
|
||||||
|
|
||||||
oclass = GST_ELEMENT_GET_CLASS (element);
|
oclass = GST_ELEMENT_GET_CLASS (element);
|
||||||
|
|
||||||
if (oclass->get_state)
|
if (oclass->get_state)
|
||||||
return (oclass->get_state) (element, state, pending, timeout);
|
result = (oclass->get_state) (element, state, pending, timeout);
|
||||||
|
|
||||||
return FALSE;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1499,6 +1616,10 @@ gst_element_get_state (GstElement * element,
|
||||||
* Abort the state change of the element. This function is used
|
* Abort the state change of the element. This function is used
|
||||||
* by elements that do asynchronous state changes and find out
|
* by elements that do asynchronous state changes and find out
|
||||||
* something is wrong.
|
* something is wrong.
|
||||||
|
*
|
||||||
|
* This function should be called with the STATE_LOCK held.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
gst_element_abort_state (GstElement * element)
|
gst_element_abort_state (GstElement * element)
|
||||||
|
@ -1528,6 +1649,10 @@ gst_element_abort_state (GstElement * element)
|
||||||
*
|
*
|
||||||
* Commit the state change of the element. This function is used
|
* Commit the state change of the element. This function is used
|
||||||
* by elements that do asynchronous state changes.
|
* by elements that do asynchronous state changes.
|
||||||
|
*
|
||||||
|
* This function can only be called with the STATE_LOCK held.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
gst_element_commit_state (GstElement * element)
|
gst_element_commit_state (GstElement * element)
|
||||||
|
@ -1563,8 +1688,9 @@ gst_element_commit_state (GstElement * element)
|
||||||
* requested state by going through all the intermediary states and calling
|
* requested state by going through all the intermediary states and calling
|
||||||
* the class's state change function for each.
|
* the class's state change function for each.
|
||||||
*
|
*
|
||||||
* Returns: TRUE if the state was successfully set.
|
* Returns: Result of the state change using #GstElementStateReturn.
|
||||||
* (using #GstElementStateReturn).
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstElementStateReturn
|
GstElementStateReturn
|
||||||
gst_element_set_state (GstElement * element, GstElementState state)
|
gst_element_set_state (GstElement * element, GstElementState state)
|
||||||
|
@ -1575,9 +1701,6 @@ gst_element_set_state (GstElement * element, GstElementState state)
|
||||||
|
|
||||||
oclass = GST_ELEMENT_GET_CLASS (element);
|
oclass = GST_ELEMENT_GET_CLASS (element);
|
||||||
|
|
||||||
/* reentrancy issues with signals in change_state) */
|
|
||||||
gst_object_ref (GST_OBJECT (element));
|
|
||||||
|
|
||||||
/* get the element state lock */
|
/* get the element state lock */
|
||||||
GST_STATE_LOCK (element);
|
GST_STATE_LOCK (element);
|
||||||
|
|
||||||
|
@ -1657,17 +1780,18 @@ exit:
|
||||||
|
|
||||||
GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "exit state change");
|
GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "exit state change");
|
||||||
|
|
||||||
gst_object_unref (GST_OBJECT (element));
|
|
||||||
|
|
||||||
return return_val;
|
return return_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* is called with STATE_LOCK */
|
||||||
|
/* FIXME make MT safe */
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_element_pads_activate (GstElement * element, gboolean active)
|
gst_element_pads_activate (GstElement * element, gboolean active)
|
||||||
{
|
{
|
||||||
GList *pads = element->pads;
|
GList *pads;
|
||||||
gboolean result = TRUE;
|
gboolean result = TRUE;
|
||||||
|
|
||||||
|
pads = element->pads;
|
||||||
while (pads && result) {
|
while (pads && result) {
|
||||||
GstPad *pad = GST_PAD (pads->data);
|
GstPad *pad = GST_PAD (pads->data);
|
||||||
|
|
||||||
|
@ -1682,6 +1806,8 @@ gst_element_pads_activate (GstElement * element, gboolean active)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* is called with STATE_LOCK */
|
||||||
|
/* FIXME make MT safe */
|
||||||
static GstElementStateReturn
|
static GstElementStateReturn
|
||||||
gst_element_change_state (GstElement * element)
|
gst_element_change_state (GstElement * element)
|
||||||
{
|
{
|
||||||
|
@ -1771,6 +1897,8 @@ gst_element_dispose (GObject * object)
|
||||||
|
|
||||||
GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "dispose");
|
GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "dispose");
|
||||||
|
|
||||||
|
/* ref so we don't hit 0 again */
|
||||||
|
gst_object_ref (GST_OBJECT (object));
|
||||||
gst_element_set_state (element, GST_STATE_NULL);
|
gst_element_set_state (element, GST_STATE_NULL);
|
||||||
|
|
||||||
/* first we break all our links with the ouside */
|
/* first we break all our links with the ouside */
|
||||||
|
@ -1778,15 +1906,18 @@ gst_element_dispose (GObject * object)
|
||||||
gst_element_remove_pad (element, GST_PAD (element->pads->data));
|
gst_element_remove_pad (element, GST_PAD (element->pads->data));
|
||||||
}
|
}
|
||||||
|
|
||||||
element->numsrcpads = 0;
|
g_assert (element->pads == 0);
|
||||||
element->numsinkpads = 0;
|
|
||||||
element->numpads = 0;
|
GST_LOCK (element);
|
||||||
|
gst_object_replace ((GstObject **) & element->manager, NULL);
|
||||||
|
gst_object_replace ((GstObject **) & element->clock, NULL);
|
||||||
|
GST_UNLOCK (element);
|
||||||
|
|
||||||
|
GST_STATE_LOCK (element);
|
||||||
if (element->state_cond)
|
if (element->state_cond)
|
||||||
g_cond_free (element->state_cond);
|
g_cond_free (element->state_cond);
|
||||||
element->state_cond = NULL;
|
element->state_cond = NULL;
|
||||||
|
GST_STATE_UNLOCK (element);
|
||||||
gst_object_replace ((GstObject **) & element->manager, NULL);
|
|
||||||
gst_object_replace ((GstObject **) & element->clock, NULL);
|
|
||||||
|
|
||||||
GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "dispose parent");
|
GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "dispose parent");
|
||||||
|
|
||||||
|
@ -1936,9 +2067,9 @@ gst_element_set_manager_func (GstElement * element, GstPipeline * manager)
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, element, "setting manager to %p",
|
GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, element, "setting manager to %p",
|
||||||
manager);
|
manager);
|
||||||
|
|
||||||
|
/* setting the manager cannot increase the refcount */
|
||||||
GST_LOCK (element);
|
GST_LOCK (element);
|
||||||
gst_object_replace ((GstObject **) & GST_ELEMENT_MANAGER (element),
|
GST_ELEMENT_MANAGER (element) = manager;
|
||||||
GST_OBJECT (manager));
|
|
||||||
GST_UNLOCK (element);
|
GST_UNLOCK (element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1949,6 +2080,8 @@ gst_element_set_manager_func (GstElement * element, GstPipeline * manager)
|
||||||
*
|
*
|
||||||
* Sets the manager of the element. For internal use only, unless you're
|
* Sets the manager of the element. For internal use only, unless you're
|
||||||
* writing a new bin subclass.
|
* writing a new bin subclass.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
gst_element_set_manager (GstElement * element, GstPipeline * manager)
|
gst_element_set_manager (GstElement * element, GstPipeline * manager)
|
||||||
|
@ -1969,7 +2102,7 @@ gst_element_set_manager (GstElement * element, GstPipeline * manager)
|
||||||
*
|
*
|
||||||
* Returns the manager of the element.
|
* Returns the manager of the element.
|
||||||
*
|
*
|
||||||
* Returns: the element's #GstPipeline.
|
* Returns: the element's #GstPipeline. unref after usage.
|
||||||
*
|
*
|
||||||
* MT safe.
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
|
@ -1982,6 +2115,7 @@ gst_element_get_manager (GstElement * element)
|
||||||
|
|
||||||
GST_LOCK (element);
|
GST_LOCK (element);
|
||||||
result = GST_ELEMENT_MANAGER (element);
|
result = GST_ELEMENT_MANAGER (element);
|
||||||
|
gst_object_ref (GST_OBJECT (result));
|
||||||
GST_UNLOCK (element);
|
GST_UNLOCK (element);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -279,7 +279,7 @@ GstTask* gst_element_create_task (GstElement *element, GstTaskFunction func, g
|
||||||
|
|
||||||
/* pad management */
|
/* pad management */
|
||||||
gboolean gst_element_add_pad (GstElement *element, GstPad *pad);
|
gboolean gst_element_add_pad (GstElement *element, GstPad *pad);
|
||||||
void gst_element_remove_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);
|
GstPad * gst_element_add_ghost_pad (GstElement *element, GstPad *pad, const gchar *name);
|
||||||
void gst_element_no_more_pads (GstElement *element);
|
void gst_element_no_more_pads (GstElement *element);
|
||||||
|
|
||||||
|
@ -288,8 +288,6 @@ GstPad* gst_element_get_static_pad (GstElement *element, const gchar *name);
|
||||||
GstPad* gst_element_get_request_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);
|
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);
|
GstIterator* gst_element_iterate_pads (GstElement *element);
|
||||||
|
|
||||||
/* event/query/format stuff */
|
/* event/query/format stuff */
|
||||||
|
|
|
@ -58,6 +58,78 @@ gst_iterator_new (guint size,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* list iterator
|
||||||
|
*/
|
||||||
|
typedef struct _GstListIterator
|
||||||
|
{
|
||||||
|
GstIterator iterator;
|
||||||
|
gpointer owner;
|
||||||
|
GList **orig;
|
||||||
|
GList *list; /* pointer in list */
|
||||||
|
GstIteratorRefFunction reffunc;
|
||||||
|
GstIteratorUnrefFunction unreffunc;
|
||||||
|
GstIteratorDisposeFunction freefunc;
|
||||||
|
} GstListIterator;
|
||||||
|
|
||||||
|
static GstIteratorResult
|
||||||
|
gst_list_iterator_next (GstListIterator * it, gpointer * elem)
|
||||||
|
{
|
||||||
|
if (it->list == NULL)
|
||||||
|
return GST_ITERATOR_DONE;
|
||||||
|
|
||||||
|
*elem = it->list->data;
|
||||||
|
if (it->reffunc) {
|
||||||
|
it->reffunc (*elem);
|
||||||
|
}
|
||||||
|
it->list = g_list_next (it->list);
|
||||||
|
|
||||||
|
return GST_ITERATOR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_list_iterator_resync (GstListIterator * it)
|
||||||
|
{
|
||||||
|
it->list = *it->orig;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_list_iterator_free (GstListIterator * it)
|
||||||
|
{
|
||||||
|
if (it->freefunc) {
|
||||||
|
it->freefunc (it->owner);
|
||||||
|
}
|
||||||
|
g_free (it);
|
||||||
|
}
|
||||||
|
|
||||||
|
GstIterator *
|
||||||
|
gst_iterator_new_list (GMutex * lock,
|
||||||
|
guint32 * master_cookie,
|
||||||
|
GList ** list,
|
||||||
|
gpointer owner,
|
||||||
|
GstIteratorRefFunction ref,
|
||||||
|
GstIteratorUnrefFunction unref, GstIteratorDisposeFunction free)
|
||||||
|
{
|
||||||
|
GstListIterator *result;
|
||||||
|
|
||||||
|
/* no need to lock, nothing can change here */
|
||||||
|
result = (GstListIterator *) gst_iterator_new (sizeof (GstListIterator),
|
||||||
|
lock,
|
||||||
|
master_cookie,
|
||||||
|
(GstIteratorNextFunction) gst_list_iterator_next,
|
||||||
|
(GstIteratorResyncFunction) gst_list_iterator_resync,
|
||||||
|
(GstIteratorFreeFunction) gst_list_iterator_free);
|
||||||
|
|
||||||
|
result->owner = owner;
|
||||||
|
result->orig = list;
|
||||||
|
result->list = *list;
|
||||||
|
result->reffunc = ref;
|
||||||
|
result->unreffunc = unref;
|
||||||
|
result->freefunc = free;
|
||||||
|
|
||||||
|
return GST_ITERATOR (result);
|
||||||
|
}
|
||||||
|
|
||||||
GstIteratorResult
|
GstIteratorResult
|
||||||
gst_iterator_next (GstIterator * it, gpointer * elem)
|
gst_iterator_next (GstIterator * it, gpointer * elem)
|
||||||
{
|
{
|
||||||
|
|
|
@ -35,6 +35,10 @@ typedef enum {
|
||||||
|
|
||||||
typedef struct _GstIterator GstIterator;
|
typedef struct _GstIterator GstIterator;
|
||||||
|
|
||||||
|
typedef void (*GstIteratorRefFunction) (gpointer item);
|
||||||
|
typedef void (*GstIteratorUnrefFunction) (gpointer item);
|
||||||
|
typedef void (*GstIteratorDisposeFunction) (gpointer owner);
|
||||||
|
|
||||||
typedef GstIteratorResult (*GstIteratorNextFunction) (GstIterator *it, gpointer *result);
|
typedef GstIteratorResult (*GstIteratorNextFunction) (GstIterator *it, gpointer *result);
|
||||||
typedef void (*GstIteratorResyncFunction) (GstIterator *it);
|
typedef void (*GstIteratorResyncFunction) (GstIterator *it);
|
||||||
typedef void (*GstIteratorFreeFunction) (GstIterator *it);
|
typedef void (*GstIteratorFreeFunction) (GstIterator *it);
|
||||||
|
@ -64,7 +68,11 @@ GstIterator* gst_iterator_new (guint size,
|
||||||
|
|
||||||
GstIterator* gst_iterator_new_list (GMutex *lock,
|
GstIterator* gst_iterator_new_list (GMutex *lock,
|
||||||
guint32 *master_cookie,
|
guint32 *master_cookie,
|
||||||
GList *list);
|
GList **list,
|
||||||
|
gpointer owner,
|
||||||
|
GstIteratorRefFunction ref,
|
||||||
|
GstIteratorUnrefFunction unref,
|
||||||
|
GstIteratorDisposeFunction free);
|
||||||
|
|
||||||
GstIteratorResult gst_iterator_next (GstIterator *it, gpointer *result);
|
GstIteratorResult gst_iterator_next (GstIterator *it, gpointer *result);
|
||||||
void gst_iterator_resync (GstIterator *it);
|
void gst_iterator_resync (GstIterator *it);
|
||||||
|
|
|
@ -61,12 +61,17 @@ _gst_message_copy (GstMessage * message)
|
||||||
{
|
{
|
||||||
GstMessage *copy;
|
GstMessage *copy;
|
||||||
|
|
||||||
|
GST_CAT_INFO (GST_CAT_MESSAGE, "copy message %p", message);
|
||||||
|
|
||||||
copy = gst_mem_chunk_alloc (chunk);
|
copy = gst_mem_chunk_alloc (chunk);
|
||||||
#ifndef GST_DISABLE_TRACE
|
#ifndef GST_DISABLE_TRACE
|
||||||
gst_alloc_trace_new (_message_trace, copy);
|
gst_alloc_trace_new (_message_trace, copy);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
memcpy (copy, message, sizeof (GstMessage));
|
memcpy (copy, message, sizeof (GstMessage));
|
||||||
|
if (GST_MESSAGE_SRC (copy)) {
|
||||||
|
gst_object_ref (GST_MESSAGE_SRC (copy));
|
||||||
|
}
|
||||||
|
|
||||||
/* FIXME copy/ref additional fields */
|
/* FIXME copy/ref additional fields */
|
||||||
switch (GST_MESSAGE_TYPE (message)) {
|
switch (GST_MESSAGE_TYPE (message)) {
|
||||||
|
|
200
gst/gstobject.c
200
gst/gstobject.c
|
@ -30,6 +30,17 @@
|
||||||
#include "gsttrace.h"
|
#include "gsttrace.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define DEBUG_REFCOUNT
|
||||||
|
#define REFCOUNT_HACK
|
||||||
|
|
||||||
|
#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 */
|
/* Object signals and args */
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -162,6 +173,7 @@ gst_object_class_init (GstObjectClass * klass)
|
||||||
G_TYPE_PARAM);
|
G_TYPE_PARAM);
|
||||||
|
|
||||||
klass->path_string_separator = "/";
|
klass->path_string_separator = "/";
|
||||||
|
klass->lock = g_mutex_new ();
|
||||||
|
|
||||||
klass->signal_object = g_object_new (gst_signal_object_get_type (), NULL);
|
klass->signal_object = g_object_new (gst_signal_object_get_type (), NULL);
|
||||||
|
|
||||||
|
@ -183,6 +195,10 @@ gst_object_init (GstObject * object)
|
||||||
|
|
||||||
object->parent = NULL;
|
object->parent = NULL;
|
||||||
object->name = NULL;
|
object->name = NULL;
|
||||||
|
gst_atomic_int_init (&(object)->refcount, 1);
|
||||||
|
#ifdef REFCOUNT_HACK
|
||||||
|
PATCH_REFCOUNT (object);
|
||||||
|
#endif
|
||||||
|
|
||||||
object->flags = 0;
|
object->flags = 0;
|
||||||
GST_FLAG_SET (object, GST_OBJECT_FLOATING);
|
GST_FLAG_SET (object, GST_OBJECT_FLOATING);
|
||||||
|
@ -229,11 +245,25 @@ gst_object_ref (GstObject * object)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
|
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",
|
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 */
|
/* FIXME, not MT safe because glib is not MT safe */
|
||||||
g_object_ref (G_OBJECT (object));
|
g_object_ref (object);
|
||||||
|
#endif
|
||||||
|
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,18 +274,50 @@ gst_object_ref (GstObject * object)
|
||||||
* Decrements the refence count on the object. If reference count hits
|
* Decrements the refence count on the object. If reference count hits
|
||||||
* zero, destroy the object. This function does not take the lock
|
* zero, destroy the object. This function does not take the lock
|
||||||
* on the object as it relies on atomic refcounting.
|
* 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)
|
gst_object_unref (GstObject * object)
|
||||||
{
|
{
|
||||||
g_return_if_fail (GST_IS_OBJECT (object));
|
g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
|
||||||
g_return_if_fail (G_OBJECT (object)->ref_count > 0);
|
|
||||||
|
|
||||||
|
#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",
|
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
|
||||||
|
|
||||||
/* FIXME, not MT safe because glib is not MT safe */
|
#ifdef REFCOUNT_HACK
|
||||||
g_object_unref (G_OBJECT (object));
|
if (G_UNLIKELY (gst_atomic_int_dec_and_test (&object->refcount))) {
|
||||||
|
PATCH_REFCOUNT1 (object);
|
||||||
|
g_object_unref (object);
|
||||||
|
} else {
|
||||||
|
PATCH_REFCOUNT (object);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
g_object_unref (object);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -279,11 +341,14 @@ gst_object_sink (GstObject * object)
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "sink");
|
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "sink");
|
||||||
|
|
||||||
GST_LOCK (object);
|
GST_LOCK (object);
|
||||||
if (GST_OBJECT_IS_FLOATING (object)) {
|
if (G_LIKELY (GST_OBJECT_IS_FLOATING (object))) {
|
||||||
GST_FLAG_UNSET (object, GST_OBJECT_FLOATING);
|
GST_FLAG_UNSET (object, GST_OBJECT_FLOATING);
|
||||||
gst_object_unref (object);
|
|
||||||
}
|
|
||||||
GST_UNLOCK (object);
|
GST_UNLOCK (object);
|
||||||
|
gst_object_unref (object);
|
||||||
|
} else {
|
||||||
|
GST_UNLOCK (object);
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -304,13 +369,23 @@ gst_object_replace (GstObject ** oldobj, GstObject * newobj)
|
||||||
g_return_if_fail (*oldobj == NULL || GST_IS_OBJECT (*oldobj));
|
g_return_if_fail (*oldobj == NULL || GST_IS_OBJECT (*oldobj));
|
||||||
g_return_if_fail (newobj == NULL || GST_IS_OBJECT (newobj));
|
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)",
|
GST_CAT_LOG (GST_CAT_REFCOUNTING, "replace %s (%d) with %s (%d)",
|
||||||
*oldobj ? GST_STR_NULL (GST_OBJECT_NAME (*oldobj)) : "(NONE)",
|
*oldobj ? GST_STR_NULL (GST_OBJECT_NAME (*oldobj)) : "(NONE)",
|
||||||
*oldobj ? G_OBJECT (*oldobj)->ref_count : 0,
|
*oldobj ? G_OBJECT (*oldobj)->ref_count : 0,
|
||||||
newobj ? GST_STR_NULL (GST_OBJECT_NAME (newobj)) : "(NONE)",
|
newobj ? GST_STR_NULL (GST_OBJECT_NAME (newobj)) : "(NONE)",
|
||||||
newobj ? G_OBJECT (newobj)->ref_count : 0);
|
newobj ? G_OBJECT (newobj)->ref_count : 0);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
if (*oldobj != newobj) {
|
if (G_UNLIKELY (*oldobj != newobj)) {
|
||||||
if (newobj)
|
if (newobj)
|
||||||
gst_object_ref (newobj);
|
gst_object_ref (newobj);
|
||||||
if (*oldobj)
|
if (*oldobj)
|
||||||
|
@ -320,15 +395,23 @@ gst_object_replace (GstObject ** oldobj, GstObject * newobj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* dispose is called when the object has to release all links
|
||||||
|
* to other objects */
|
||||||
static void
|
static void
|
||||||
gst_object_dispose (GObject * object)
|
gst_object_dispose (GObject * object)
|
||||||
{
|
{
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "dispose");
|
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "dispose");
|
||||||
|
|
||||||
|
GST_LOCK (object);
|
||||||
GST_FLAG_SET (GST_OBJECT (object), GST_OBJECT_DESTROYED);
|
GST_FLAG_SET (GST_OBJECT (object), GST_OBJECT_DESTROYED);
|
||||||
GST_OBJECT_PARENT (object) = NULL;
|
GST_OBJECT_PARENT (object) = NULL;
|
||||||
|
GST_UNLOCK (object);
|
||||||
|
|
||||||
|
/* need to patch refcount so it is finalized */
|
||||||
|
PATCH_REFCOUNT1 (object)
|
||||||
|
|
||||||
parent_class->dispose (object);
|
parent_class->dispose (object);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* finalize is called when the object has to free its resources */
|
/* finalize is called when the object has to free its resources */
|
||||||
|
@ -359,49 +442,62 @@ gst_object_finalize (GObject * object)
|
||||||
parent_class->finalize (object);
|
parent_class->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME a class wide mutex is enough */
|
|
||||||
static GStaticRecMutex dispatch_mutex = G_STATIC_REC_MUTEX_INIT;
|
|
||||||
|
|
||||||
/* Changing a GObject property of a GstObject will result in "deep_notify"
|
/* Changing a GObject property of a GstObject will result in "deep_notify"
|
||||||
* signals being emitted by the object itself, as well as in each parent
|
* 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
|
* object. This is so that an application can connect a listener to the
|
||||||
* top-level bin to catch property-change notifications for all contained
|
* 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
|
static void
|
||||||
gst_object_dispatch_properties_changed (GObject * object,
|
gst_object_dispatch_properties_changed (GObject * object,
|
||||||
guint n_pspecs, GParamSpec ** pspecs)
|
guint n_pspecs, GParamSpec ** pspecs)
|
||||||
{
|
{
|
||||||
GstObject *gst_object, *parent, *old_parent;
|
GstObject *gst_object, *parent, *old_parent;
|
||||||
guint i;
|
guint i;
|
||||||
const gchar *name;
|
gchar *name, *debug_name;
|
||||||
|
GstObjectClass *klass;
|
||||||
g_static_rec_mutex_lock (&dispatch_mutex);
|
|
||||||
/* do the standard dispatching */
|
|
||||||
G_OBJECT_CLASS (parent_class)->dispatch_properties_changed (object, n_pspecs,
|
|
||||||
pspecs);
|
|
||||||
|
|
||||||
/* we fail when this is not a GstObject */
|
/* we fail when this is not a GstObject */
|
||||||
g_return_if_fail (GST_IS_OBJECT (object));
|
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);
|
gst_object = GST_OBJECT_CAST (object);
|
||||||
name = gst_object_get_name (gst_object);
|
name = gst_object_get_name (gst_object);
|
||||||
|
debug_name = GST_STR_NULL (name);
|
||||||
|
|
||||||
/* now let the parent dispatch those, too */
|
/* now let the parent dispatch those, too */
|
||||||
parent = gst_object_get_parent (gst_object);
|
parent = gst_object_get_parent (gst_object);
|
||||||
while (parent) {
|
while (parent) {
|
||||||
/* for debugging ... */
|
/* for debugging ... */
|
||||||
gchar *parent_name = gst_object_get_name (parent);
|
gchar *parent_name = gst_object_get_name (parent);
|
||||||
|
gchar *debug_parent_name = GST_STR_NULL (parent_name);
|
||||||
|
|
||||||
/* need own category? */
|
/* need own category? */
|
||||||
for (i = 0; i < n_pspecs; i++) {
|
for (i = 0; i < n_pspecs; i++) {
|
||||||
GST_CAT_LOG (GST_CAT_EVENT, "deep notification from %s to %s (%s)",
|
GST_CAT_LOG (GST_CAT_EVENT, "deep notification from %s to %s (%s)",
|
||||||
name ? name : "(null)",
|
debug_name, debug_parent_name, pspecs[i]->name);
|
||||||
parent_name ? parent_name : "(null)", pspecs[i]->name);
|
|
||||||
|
|
||||||
/* FIXME, not MT safe because of glib */
|
/* 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_signal_emit (parent, gst_object_signals[DEEP_NOTIFY],
|
||||||
g_quark_from_string (pspecs[i]->name), GST_OBJECT_CAST (object),
|
g_quark_from_string (pspecs[i]->name), GST_OBJECT_CAST (object),
|
||||||
pspecs[i]);
|
pspecs[i]);
|
||||||
|
PATCH_REFCOUNT (parent);
|
||||||
|
PATCH_REFCOUNT (object);
|
||||||
}
|
}
|
||||||
g_free (parent_name);
|
g_free (parent_name);
|
||||||
|
|
||||||
|
@ -409,7 +505,8 @@ gst_object_dispatch_properties_changed (GObject * object,
|
||||||
parent = gst_object_get_parent (old_parent);
|
parent = gst_object_get_parent (old_parent);
|
||||||
gst_object_unref (old_parent);
|
gst_object_unref (old_parent);
|
||||||
}
|
}
|
||||||
g_static_rec_mutex_unlock (&dispatch_mutex);
|
g_free (name);
|
||||||
|
GST_CLASS_UNLOCK (klass);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -425,6 +522,8 @@ gst_object_dispatch_properties_changed (GObject * object,
|
||||||
* strings that should be excluded from the notify.
|
* strings that should be excluded from the notify.
|
||||||
* The default handler will print the new value of the property
|
* The default handler will print the new value of the property
|
||||||
* using g_print.
|
* using g_print.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
gst_object_default_deep_notify (GObject * object, GstObject * orig,
|
gst_object_default_deep_notify (GObject * object, GstObject * orig,
|
||||||
|
@ -564,45 +663,48 @@ gst_object_get_name (GstObject * object)
|
||||||
* Sets the parent of @object. The object's reference count will be incremented,
|
* Sets the parent of @object. The object's reference count will be incremented,
|
||||||
* and any floating reference will be removed (see gst_object_sink()).
|
* 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.
|
* 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.
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
void
|
gboolean
|
||||||
gst_object_set_parent (GstObject * object, GstObject * parent)
|
gst_object_set_parent (GstObject * object, GstObject * parent)
|
||||||
{
|
{
|
||||||
g_return_if_fail (GST_IS_OBJECT (object));
|
g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
|
||||||
g_return_if_fail (GST_IS_OBJECT (parent));
|
g_return_val_if_fail (GST_IS_OBJECT (parent), FALSE);
|
||||||
g_return_if_fail (object != parent);
|
g_return_val_if_fail (object != parent, FALSE);
|
||||||
|
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "set parent (ref and sink)");
|
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "set parent (ref and sink)");
|
||||||
|
|
||||||
/* no need to hold locks here as object is either floating and
|
|
||||||
* owned by this thread only or has a refcount bigger than 1 when
|
|
||||||
* concurrent access is performed */
|
|
||||||
gst_object_ref (object);
|
|
||||||
GST_LOCK (object);
|
GST_LOCK (object);
|
||||||
if G_UNLIKELY
|
if (G_UNLIKELY (object->parent != NULL))
|
||||||
(object->parent != NULL)
|
|
||||||
goto had_parent;
|
goto had_parent;
|
||||||
|
|
||||||
/* sink object, we don't call our own function because we don't
|
/* sink object, we don't call our own function because we don't
|
||||||
* need to release/acquire the lock needlessly */
|
* need to release/acquire the lock needlessly or touch the refcount
|
||||||
if (GST_OBJECT_IS_FLOATING (object)) {
|
* in the floating case. */
|
||||||
GST_FLAG_UNSET (object, GST_OBJECT_FLOATING);
|
|
||||||
gst_object_unref (object);
|
|
||||||
}
|
|
||||||
object->parent = parent;
|
object->parent = parent;
|
||||||
|
if (G_LIKELY (GST_OBJECT_IS_FLOATING (object))) {
|
||||||
|
GST_FLAG_UNSET (object, GST_OBJECT_FLOATING);
|
||||||
GST_UNLOCK (object);
|
GST_UNLOCK (object);
|
||||||
|
} else {
|
||||||
|
GST_UNLOCK (object);
|
||||||
|
gst_object_ref (object);
|
||||||
|
}
|
||||||
|
|
||||||
g_signal_emit (G_OBJECT (object), gst_object_signals[PARENT_SET], 0, parent);
|
g_signal_emit (G_OBJECT (object), gst_object_signals[PARENT_SET], 0, parent);
|
||||||
return;
|
return TRUE;
|
||||||
|
|
||||||
had_parent:
|
had_parent:
|
||||||
GST_UNLOCK (object);
|
GST_UNLOCK (object);
|
||||||
g_critical ("object already had a parent");
|
|
||||||
|
|
||||||
return;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -626,7 +728,7 @@ gst_object_get_parent (GstObject * object)
|
||||||
|
|
||||||
GST_LOCK (object);
|
GST_LOCK (object);
|
||||||
result = object->parent;
|
result = object->parent;
|
||||||
if (result)
|
if (G_LIKELY (result))
|
||||||
gst_object_ref (result);
|
gst_object_ref (result);
|
||||||
GST_UNLOCK (object);
|
GST_UNLOCK (object);
|
||||||
|
|
||||||
|
@ -653,17 +755,18 @@ gst_object_unparent (GstObject * object)
|
||||||
GST_LOCK (object);
|
GST_LOCK (object);
|
||||||
parent = object->parent;
|
parent = object->parent;
|
||||||
|
|
||||||
if G_LIKELY
|
if (G_LIKELY (parent != NULL)) {
|
||||||
(parent != NULL) {
|
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "unparent");
|
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "unparent");
|
||||||
object->parent = NULL;
|
object->parent = NULL;
|
||||||
}
|
|
||||||
GST_UNLOCK (object);
|
GST_UNLOCK (object);
|
||||||
|
|
||||||
g_signal_emit (G_OBJECT (object), gst_object_signals[PARENT_UNSET], 0,
|
g_signal_emit (G_OBJECT (object), gst_object_signals[PARENT_UNSET], 0,
|
||||||
parent);
|
parent);
|
||||||
|
|
||||||
gst_object_unref (object);
|
gst_object_unref (object);
|
||||||
|
} else {
|
||||||
|
GST_UNLOCK (object);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -835,6 +938,7 @@ gst_object_get_path_string (GstObject * object)
|
||||||
parent = gst_object_get_parent (object);
|
parent = gst_object_get_parent (object);
|
||||||
/* add parents to list, refcount remains increased while
|
/* add parents to list, refcount remains increased while
|
||||||
* we handle the object */
|
* we handle the object */
|
||||||
|
if (parent)
|
||||||
parentage = g_slist_prepend (parentage, parent);
|
parentage = g_slist_prepend (parentage, parent);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
|
|
||||||
#include <glib-object.h> /* note that this gets wrapped in __GST_OBJECT_H__ */
|
#include <glib-object.h> /* note that this gets wrapped in __GST_OBJECT_H__ */
|
||||||
|
|
||||||
|
#include <gst/gstatomic.h>
|
||||||
#include <gst/gsttypes.h>
|
#include <gst/gsttypes.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
@ -42,6 +43,7 @@ GST_EXPORT GType _gst_object_type;
|
||||||
#define GST_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_OBJECT, GstObject))
|
#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_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_OBJECT, GstObjectClass))
|
||||||
#define GST_OBJECT_CAST(obj) ((GstObject*)(obj))
|
#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
|
/* make sure we don't change the object size but stil make it compile
|
||||||
* without libxml */
|
* without libxml */
|
||||||
|
@ -51,12 +53,16 @@ GST_EXPORT GType _gst_object_type;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
GST_OBJECT_DESTROYED = 0,
|
GST_OBJECT_DISPOSING = 0,
|
||||||
|
GST_OBJECT_DESTROYED = 1,
|
||||||
GST_OBJECT_FLOATING,
|
GST_OBJECT_FLOATING,
|
||||||
|
|
||||||
GST_OBJECT_FLAG_LAST = 4
|
GST_OBJECT_FLAG_LAST = 4
|
||||||
} GstObjectFlags;
|
} 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
|
/* we do a GST_OBJECT_CAST to avoid type checking, better call these
|
||||||
* function with a valid object! */
|
* function with a valid object! */
|
||||||
#define GST_LOCK(obj) (g_mutex_lock(GST_OBJECT_CAST(obj)->lock))
|
#define GST_LOCK(obj) (g_mutex_lock(GST_OBJECT_CAST(obj)->lock))
|
||||||
|
@ -67,8 +73,9 @@ typedef enum
|
||||||
#define GST_OBJECT_NAME(obj) (GST_OBJECT_CAST(obj)->name)
|
#define GST_OBJECT_NAME(obj) (GST_OBJECT_CAST(obj)->name)
|
||||||
#define GST_OBJECT_PARENT(obj) (GST_OBJECT_CAST(obj)->parent)
|
#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_FLAGS(obj) (GST_OBJECT_CAST (obj)->flags)
|
||||||
#define GST_FLAG_IS_SET(obj,flag) (GST_FLAGS (obj) & (1<<(flag)))
|
#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_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_FLAG_UNSET(obj,flag) G_STMT_START{ (GST_FLAGS (obj) &= ~(1<<(flag))); }G_STMT_END
|
||||||
|
|
||||||
|
@ -78,16 +85,25 @@ typedef enum
|
||||||
struct _GstObject {
|
struct _GstObject {
|
||||||
GObject object;
|
GObject object;
|
||||||
|
|
||||||
|
/*< public >*/
|
||||||
|
GstAtomicInt refcount;
|
||||||
|
|
||||||
/*< public >*/ /* with LOCK */
|
/*< public >*/ /* with LOCK */
|
||||||
GMutex *lock; /* locking for all sorts of things */
|
GMutex *lock; /* locking for all sorts of things */
|
||||||
gchar *name; /* name */
|
gchar *name; /* name */
|
||||||
GstObject *parent; /* this object's parent */
|
GstObject *parent; /* this object's parent, no refcount is held for the parent. */
|
||||||
guint32 flags;
|
guint32 flags;
|
||||||
|
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
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 */
|
/* signal_object is used to signal to the whole class */
|
||||||
struct _GstObjectClass {
|
struct _GstObjectClass {
|
||||||
GObjectClass parent_class;
|
GObjectClass parent_class;
|
||||||
|
@ -95,6 +111,8 @@ struct _GstObjectClass {
|
||||||
gchar *path_string_separator;
|
gchar *path_string_separator;
|
||||||
GObject *signal_object;
|
GObject *signal_object;
|
||||||
|
|
||||||
|
GMutex *lock;
|
||||||
|
|
||||||
/* signals */
|
/* signals */
|
||||||
void (*parent_set) (GstObject *object, GstObject *parent);
|
void (*parent_set) (GstObject *object, GstObject *parent);
|
||||||
void (*parent_unset) (GstObject *object, GstObject *parent);
|
void (*parent_unset) (GstObject *object, GstObject *parent);
|
||||||
|
@ -111,9 +129,6 @@ struct _GstObjectClass {
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
gpointer _gst_reserved[GST_PADDING];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* normal GObject stuff */
|
/* normal GObject stuff */
|
||||||
GType gst_object_get_type (void);
|
GType gst_object_get_type (void);
|
||||||
|
|
||||||
|
@ -122,7 +137,7 @@ void gst_object_set_name (GstObject *object, const gchar *name);
|
||||||
gchar* gst_object_get_name (GstObject *object);
|
gchar* gst_object_get_name (GstObject *object);
|
||||||
|
|
||||||
/* parentage routines */
|
/* 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);
|
GstObject* gst_object_get_parent (GstObject *object);
|
||||||
void gst_object_unparent (GstObject *object);
|
void gst_object_unparent (GstObject *object);
|
||||||
|
|
||||||
|
@ -131,7 +146,7 @@ void gst_object_default_deep_notify (GObject *object, GstObject *ori
|
||||||
|
|
||||||
/* refcounting + life cycle */
|
/* refcounting + life cycle */
|
||||||
GstObject * gst_object_ref (GstObject *object);
|
GstObject * gst_object_ref (GstObject *object);
|
||||||
void gst_object_unref (GstObject *object);
|
GstObject * gst_object_unref (GstObject *object);
|
||||||
void gst_object_sink (GstObject *object);
|
void gst_object_sink (GstObject *object);
|
||||||
|
|
||||||
/* replace object pointer */
|
/* replace object pointer */
|
||||||
|
|
523
gst/gstpad.c
523
gst/gstpad.c
|
@ -47,6 +47,18 @@ GST_DEBUG_CATEGORY_STATIC (debug_dataflow);
|
||||||
}G_STMT_END
|
}G_STMT_END
|
||||||
#define GST_CAT_DEFAULT GST_CAT_PADS
|
#define GST_CAT_DEFAULT GST_CAT_PADS
|
||||||
|
|
||||||
|
#define GST_PAD_REALIZE_AND_LOCK(pad, realpad, lost_ghostpad) \
|
||||||
|
GST_LOCK (pad); \
|
||||||
|
realpad = GST_PAD_REALIZE (pad); \
|
||||||
|
if (G_UNLIKELY (realpad == NULL)) { \
|
||||||
|
GST_UNLOCK (pad); \
|
||||||
|
goto lost_ghostpad; \
|
||||||
|
} \
|
||||||
|
if (G_UNLIKELY (pad != GST_PAD_CAST (realpad))) { \
|
||||||
|
GST_LOCK (realpad); \
|
||||||
|
GST_UNLOCK (pad); \
|
||||||
|
}
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
TEMPL_PAD_CREATED,
|
TEMPL_PAD_CREATED,
|
||||||
|
@ -116,6 +128,8 @@ gst_pad_dispose (GObject * object)
|
||||||
GstPad *pad = GST_PAD (object);
|
GstPad *pad = GST_PAD (object);
|
||||||
|
|
||||||
gst_pad_set_pad_template (pad, NULL);
|
gst_pad_set_pad_template (pad, NULL);
|
||||||
|
/* FIXME, we have links to many other things like caps
|
||||||
|
* and the peer pad... */
|
||||||
|
|
||||||
G_OBJECT_CLASS (pad_parent_class)->dispose (object);
|
G_OBJECT_CLASS (pad_parent_class)->dispose (object);
|
||||||
}
|
}
|
||||||
|
@ -425,30 +439,29 @@ gst_pad_set_active (GstPad * pad, gboolean active)
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
|
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
|
||||||
|
|
||||||
GST_LOCK (pad);
|
GST_PAD_REALIZE_AND_LOCK (pad, realpad, lost_ghostpad);
|
||||||
old = GST_PAD_IS_ACTIVE (pad);
|
|
||||||
|
old = GST_PAD_IS_ACTIVE (realpad);
|
||||||
|
|
||||||
if (G_UNLIKELY (old == active))
|
if (G_UNLIKELY (old == active))
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
realpad = GST_PAD_REALIZE (pad);
|
|
||||||
|
|
||||||
/* make sure data is disallowed when going inactive */
|
/* make sure data is disallowed when going inactive */
|
||||||
if (!active) {
|
if (!active) {
|
||||||
GST_CAT_DEBUG (GST_CAT_PADS, "de-activating pad %s:%s",
|
GST_CAT_DEBUG (GST_CAT_PADS, "de-activating pad %s:%s",
|
||||||
GST_DEBUG_PAD_NAME (realpad));
|
GST_DEBUG_PAD_NAME (realpad));
|
||||||
GST_FLAG_SET (realpad, GST_PAD_DISABLED);
|
GST_FLAG_SET (realpad, GST_PAD_DISABLED);
|
||||||
/* unlock blocked pads so element can resume and stop */
|
/* unlock blocked pads so element can resume and stop */
|
||||||
GST_PAD_BLOCK_SIGNAL (pad);
|
GST_PAD_BLOCK_SIGNAL (realpad);
|
||||||
}
|
}
|
||||||
|
|
||||||
activatefunc = realpad->activatefunc;
|
activatefunc = realpad->activatefunc;
|
||||||
if (activatefunc) {
|
if (activatefunc) {
|
||||||
/* unlock so element can sync */
|
/* unlock so element can sync */
|
||||||
GST_UNLOCK (pad);
|
GST_UNLOCK (realpad);
|
||||||
result = activatefunc (pad, active);
|
result = activatefunc (GST_PAD_CAST (realpad), active);
|
||||||
/* and lock again */
|
/* and lock again */
|
||||||
GST_LOCK (pad);
|
GST_LOCK (realpad);
|
||||||
} else {
|
} else {
|
||||||
result = TRUE;
|
result = TRUE;
|
||||||
}
|
}
|
||||||
|
@ -461,9 +474,14 @@ gst_pad_set_active (GstPad * pad, gboolean active)
|
||||||
}
|
}
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
GST_UNLOCK (pad);
|
GST_UNLOCK (realpad);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
lost_ghostpad:
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -480,14 +498,20 @@ gboolean
|
||||||
gst_pad_is_active (GstPad * pad)
|
gst_pad_is_active (GstPad * pad)
|
||||||
{
|
{
|
||||||
gboolean result = FALSE;
|
gboolean result = FALSE;
|
||||||
|
GstRealPad *realpad;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
|
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
|
||||||
|
|
||||||
GST_LOCK (pad);
|
GST_PAD_REALIZE_AND_LOCK (pad, realpad, lost_ghostpad);
|
||||||
result = !GST_FLAG_IS_SET (pad, GST_PAD_DISABLED);
|
result = !GST_FLAG_IS_SET (realpad, GST_PAD_DISABLED);
|
||||||
GST_UNLOCK (pad);
|
GST_UNLOCK (realpad);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
lost_ghostpad:
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -520,36 +544,30 @@ gst_pad_set_blocked_async (GstPad * pad, gboolean blocked,
|
||||||
gboolean was_blocked;
|
gboolean was_blocked;
|
||||||
GstRealPad *realpad;
|
GstRealPad *realpad;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_REAL_PAD (pad), FALSE);
|
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
|
||||||
|
|
||||||
GST_LOCK (pad);
|
GST_PAD_REALIZE_AND_LOCK (pad, realpad, lost_ghostpad);
|
||||||
realpad = GST_PAD_REALIZE (pad);
|
|
||||||
if (GST_PAD_CAST (realpad) != pad) {
|
|
||||||
GST_LOCK (realpad);
|
|
||||||
GST_UNLOCK (pad);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* beware for turning flags into booleans */
|
was_blocked = GST_RPAD_IS_BLOCKED (realpad);
|
||||||
was_blocked = !!GST_RPAD_IS_BLOCKED (realpad);
|
|
||||||
|
|
||||||
if (G_UNLIKELY (was_blocked == blocked))
|
if (G_UNLIKELY (was_blocked == blocked))
|
||||||
goto had_right_state;
|
goto had_right_state;
|
||||||
|
|
||||||
if (blocked) {
|
if (blocked) {
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "blocking pad %s:%s",
|
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, realpad, "blocking pad %s:%s",
|
||||||
GST_DEBUG_PAD_NAME (pad));
|
GST_DEBUG_PAD_NAME (realpad));
|
||||||
|
|
||||||
GST_FLAG_SET (realpad, GST_PAD_BLOCKED);
|
GST_FLAG_SET (realpad, GST_PAD_BLOCKED);
|
||||||
realpad->block_callback = callback;
|
realpad->block_callback = callback;
|
||||||
realpad->block_data = user_data;
|
realpad->block_data = user_data;
|
||||||
if (!callback) {
|
if (!callback) {
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "waiting for block");
|
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, realpad, "waiting for block");
|
||||||
GST_PAD_BLOCK_WAIT (pad);
|
GST_PAD_BLOCK_WAIT (realpad);
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "blocked");
|
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, realpad, "blocked");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "unblocking pad %s:%s",
|
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, realpad, "unblocking pad %s:%s",
|
||||||
GST_DEBUG_PAD_NAME (pad));
|
GST_DEBUG_PAD_NAME (realpad));
|
||||||
|
|
||||||
GST_FLAG_UNSET (realpad, GST_PAD_BLOCKED);
|
GST_FLAG_UNSET (realpad, GST_PAD_BLOCKED);
|
||||||
|
|
||||||
|
@ -557,23 +575,29 @@ gst_pad_set_blocked_async (GstPad * pad, gboolean blocked,
|
||||||
realpad->block_data = user_data;
|
realpad->block_data = user_data;
|
||||||
|
|
||||||
if (callback) {
|
if (callback) {
|
||||||
GST_PAD_BLOCK_SIGNAL (pad);
|
GST_PAD_BLOCK_SIGNAL (realpad);
|
||||||
} else {
|
} else {
|
||||||
GST_PAD_BLOCK_SIGNAL (pad);
|
GST_PAD_BLOCK_SIGNAL (realpad);
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "waiting for unblock");
|
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, realpad, "waiting for unblock");
|
||||||
GST_PAD_BLOCK_WAIT (pad);
|
GST_PAD_BLOCK_WAIT (realpad);
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "unblocked");
|
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, realpad, "unblocked");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GST_UNLOCK (pad);
|
GST_UNLOCK (realpad);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
had_right_state:
|
lost_ghostpad:
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pad %s:%s was in right state",
|
{
|
||||||
GST_DEBUG_PAD_NAME (pad));
|
|
||||||
GST_UNLOCK (pad);
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
}
|
||||||
|
had_right_state:
|
||||||
|
{
|
||||||
|
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, realpad,
|
||||||
|
"pad %s:%s was in right state", GST_DEBUG_PAD_NAME (realpad));
|
||||||
|
GST_UNLOCK (realpad);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -613,14 +637,20 @@ gboolean
|
||||||
gst_pad_is_blocked (GstPad * pad)
|
gst_pad_is_blocked (GstPad * pad)
|
||||||
{
|
{
|
||||||
gboolean result = FALSE;
|
gboolean result = FALSE;
|
||||||
|
GstRealPad *realpad;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_PAD (pad), result);
|
g_return_val_if_fail (GST_IS_PAD (pad), result);
|
||||||
|
|
||||||
GST_LOCK (pad);
|
GST_PAD_REALIZE_AND_LOCK (pad, realpad, lost_ghostpad);
|
||||||
result = GST_FLAG_IS_SET (pad, GST_PAD_BLOCKED);
|
result = GST_FLAG_IS_SET (realpad, GST_PAD_BLOCKED);
|
||||||
GST_UNLOCK (pad);
|
GST_UNLOCK (realpad);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
lost_ghostpad:
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1042,26 +1072,13 @@ gst_pad_unlink (GstPad * srcpad, GstPad * sinkpad)
|
||||||
GST_DEBUG_PAD_NAME (srcpad), srcpad,
|
GST_DEBUG_PAD_NAME (srcpad), srcpad,
|
||||||
GST_DEBUG_PAD_NAME (sinkpad), sinkpad);
|
GST_DEBUG_PAD_NAME (sinkpad), sinkpad);
|
||||||
|
|
||||||
GST_LOCK (srcpad);
|
GST_PAD_REALIZE_AND_LOCK (srcpad, realsrc, lost_src_ghostpad);
|
||||||
realsrc = GST_PAD_REALIZE (srcpad);
|
|
||||||
if (srcpad != GST_PAD_CAST (realsrc)) {
|
|
||||||
GST_LOCK (realsrc);
|
|
||||||
/* we don't care if the ghostpad goes away now */
|
|
||||||
GST_UNLOCK (srcpad);
|
|
||||||
}
|
|
||||||
if (G_UNLIKELY (GST_RPAD_DIRECTION (realsrc) != GST_PAD_SRC))
|
if (G_UNLIKELY (GST_RPAD_DIRECTION (realsrc) != GST_PAD_SRC))
|
||||||
goto not_srcpad;
|
goto not_srcpad;
|
||||||
|
|
||||||
if (G_UNLIKELY (GST_RPAD_PEER (realsrc) == NULL))
|
GST_PAD_REALIZE_AND_LOCK (sinkpad, realsink, lost_sink_ghostpad);
|
||||||
goto was_unlinked;
|
|
||||||
|
|
||||||
GST_LOCK (sinkpad);
|
|
||||||
realsink = GST_PAD_REALIZE (sinkpad);
|
|
||||||
if (sinkpad != GST_PAD_CAST (realsink)) {
|
|
||||||
GST_LOCK (realsink);
|
|
||||||
/* we don't care if the ghostpad goes away now */
|
|
||||||
GST_UNLOCK (sinkpad);
|
|
||||||
}
|
|
||||||
if (G_UNLIKELY (GST_RPAD_DIRECTION (realsink) != GST_PAD_SINK))
|
if (G_UNLIKELY (GST_RPAD_DIRECTION (realsink) != GST_PAD_SINK))
|
||||||
goto not_sinkpad;
|
goto not_sinkpad;
|
||||||
|
|
||||||
|
@ -1083,8 +1100,8 @@ gst_pad_unlink (GstPad * srcpad, GstPad * sinkpad)
|
||||||
gst_caps_replace (&GST_RPAD_APPFILTER (realsrc), NULL);
|
gst_caps_replace (&GST_RPAD_APPFILTER (realsrc), NULL);
|
||||||
gst_caps_replace (&GST_RPAD_APPFILTER (realsink), NULL);
|
gst_caps_replace (&GST_RPAD_APPFILTER (realsink), NULL);
|
||||||
|
|
||||||
GST_UNLOCK (realsrc);
|
|
||||||
GST_UNLOCK (realsink);
|
GST_UNLOCK (realsink);
|
||||||
|
GST_UNLOCK (realsrc);
|
||||||
|
|
||||||
/* fire off a signal to each of the pads telling them
|
/* fire off a signal to each of the pads telling them
|
||||||
* that they've been unlinked */
|
* that they've been unlinked */
|
||||||
|
@ -1094,27 +1111,29 @@ gst_pad_unlink (GstPad * srcpad, GstPad * sinkpad)
|
||||||
0, realsrc);
|
0, realsrc);
|
||||||
|
|
||||||
GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "unlinked %s:%s and %s:%s",
|
GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "unlinked %s:%s and %s:%s",
|
||||||
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
|
GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
lost_src_ghostpad:
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
not_srcpad:
|
not_srcpad:
|
||||||
{
|
{
|
||||||
g_critical ("pad %s is not a source pad", GST_PAD_NAME (realsrc));
|
g_critical ("pad %s is not a source pad", GST_PAD_NAME (realsrc));
|
||||||
GST_UNLOCK (realsrc);
|
GST_UNLOCK (realsrc);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
lost_sink_ghostpad:
|
||||||
|
{
|
||||||
|
GST_UNLOCK (realsrc);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
not_sinkpad:
|
not_sinkpad:
|
||||||
{
|
{
|
||||||
g_critical ("pad %s is not a sink pad", GST_PAD_NAME (realsink));
|
g_critical ("pad %s is not a sink pad", GST_PAD_NAME (realsink));
|
||||||
GST_UNLOCK (realsrc);
|
|
||||||
GST_UNLOCK (realsink);
|
GST_UNLOCK (realsink);
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
was_unlinked:
|
|
||||||
{
|
|
||||||
/* we do not emit a warning in this case because unlinking cannot
|
|
||||||
* be made MT safe.*/
|
|
||||||
GST_UNLOCK (realsrc);
|
GST_UNLOCK (realsrc);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -1122,8 +1141,8 @@ not_linked_together:
|
||||||
{
|
{
|
||||||
/* we do not emit a warning in this case because unlinking cannot
|
/* we do not emit a warning in this case because unlinking cannot
|
||||||
* be made MT safe.*/
|
* be made MT safe.*/
|
||||||
GST_UNLOCK (realsrc);
|
|
||||||
GST_UNLOCK (realsink);
|
GST_UNLOCK (realsink);
|
||||||
|
GST_UNLOCK (realsrc);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1142,14 +1161,116 @@ gboolean
|
||||||
gst_pad_is_linked (GstPad * pad)
|
gst_pad_is_linked (GstPad * pad)
|
||||||
{
|
{
|
||||||
gboolean result;
|
gboolean result;
|
||||||
|
GstRealPad *realpad;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
|
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
|
||||||
|
|
||||||
GST_LOCK (pad);
|
GST_PAD_REALIZE_AND_LOCK (pad, realpad, lost_ghostpad);
|
||||||
result = (GST_PAD_PEER (pad) != NULL);
|
result = (GST_PAD_PEER (realpad) != NULL);
|
||||||
GST_UNLOCK (pad);
|
GST_UNLOCK (realpad);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
lost_ghostpad:
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstPadLinkReturn
|
||||||
|
gst_pad_link_prepare_filtered (GstPad * srcpad, GstPad * sinkpad,
|
||||||
|
GstRealPad ** outrealsrc, GstRealPad ** outrealsink,
|
||||||
|
const GstCaps * filtercaps)
|
||||||
|
{
|
||||||
|
GstRealPad *realsrc, *realsink;
|
||||||
|
|
||||||
|
/* generic checks */
|
||||||
|
g_return_val_if_fail (GST_IS_PAD (srcpad), GST_PAD_LINK_REFUSED);
|
||||||
|
g_return_val_if_fail (GST_IS_PAD (sinkpad), GST_PAD_LINK_REFUSED);
|
||||||
|
|
||||||
|
GST_CAT_INFO (GST_CAT_PADS, "trying to link %s:%s and %s:%s",
|
||||||
|
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
|
||||||
|
|
||||||
|
/* now we need to deal with the real/ghost stuff */
|
||||||
|
GST_PAD_REALIZE_AND_LOCK (srcpad, realsrc, lost_src_ghostpad);
|
||||||
|
|
||||||
|
if (G_UNLIKELY (GST_RPAD_DIRECTION (realsrc) != GST_PAD_SRC))
|
||||||
|
goto not_srcpad;
|
||||||
|
|
||||||
|
if (G_UNLIKELY (GST_RPAD_PEER (realsrc) != NULL))
|
||||||
|
goto src_was_linked;
|
||||||
|
|
||||||
|
GST_PAD_REALIZE_AND_LOCK (sinkpad, realsink, lost_sink_ghostpad);
|
||||||
|
|
||||||
|
if (G_UNLIKELY (GST_RPAD_DIRECTION (realsink) != GST_PAD_SINK))
|
||||||
|
goto not_sinkpad;
|
||||||
|
|
||||||
|
if (G_UNLIKELY (GST_RPAD_PEER (realsink) != NULL))
|
||||||
|
goto sink_was_linked;
|
||||||
|
|
||||||
|
if ((GST_PAD (realsrc) != srcpad) || (GST_PAD (realsink) != sinkpad)) {
|
||||||
|
GST_CAT_INFO (GST_CAT_PADS, "*actually* linking %s:%s and %s:%s",
|
||||||
|
GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
|
||||||
|
}
|
||||||
|
*outrealsrc = realsrc;
|
||||||
|
*outrealsink = realsink;
|
||||||
|
|
||||||
|
/* FIXME check pad caps for non-empty intersection */
|
||||||
|
|
||||||
|
/* FIXME check pad scheduling for non-empty intersection */
|
||||||
|
|
||||||
|
/* update filter */
|
||||||
|
if (filtercaps) {
|
||||||
|
GstCaps *filtercopy;
|
||||||
|
|
||||||
|
filtercopy = gst_caps_copy (filtercaps);
|
||||||
|
filtercopy = gst_caps_ref (filtercopy);
|
||||||
|
|
||||||
|
gst_caps_replace (&GST_PAD_APPFILTER (realsrc), filtercopy);
|
||||||
|
gst_caps_replace (&GST_PAD_APPFILTER (realsink), filtercopy);
|
||||||
|
} else {
|
||||||
|
gst_caps_replace (&GST_PAD_APPFILTER (realsrc), NULL);
|
||||||
|
gst_caps_replace (&GST_PAD_APPFILTER (realsink), NULL);
|
||||||
|
}
|
||||||
|
return GST_PAD_LINK_OK;
|
||||||
|
|
||||||
|
lost_src_ghostpad:
|
||||||
|
{
|
||||||
|
return GST_PAD_LINK_REFUSED;
|
||||||
|
}
|
||||||
|
not_srcpad:
|
||||||
|
{
|
||||||
|
g_critical ("pad %s is not a source pad", GST_PAD_NAME (realsrc));
|
||||||
|
GST_UNLOCK (realsrc);
|
||||||
|
return GST_PAD_LINK_WRONG_DIRECTION;
|
||||||
|
}
|
||||||
|
src_was_linked:
|
||||||
|
{
|
||||||
|
/* we do not emit a warning in this case because unlinking cannot
|
||||||
|
* be made MT safe.*/
|
||||||
|
GST_UNLOCK (realsrc);
|
||||||
|
return GST_PAD_LINK_WAS_LINKED;
|
||||||
|
}
|
||||||
|
lost_sink_ghostpad:
|
||||||
|
{
|
||||||
|
GST_DEBUG ("lost sink ghostpad");
|
||||||
|
GST_UNLOCK (realsrc);
|
||||||
|
return GST_PAD_LINK_REFUSED;
|
||||||
|
}
|
||||||
|
not_sinkpad:
|
||||||
|
{
|
||||||
|
g_critical ("pad %s is not a sink pad", GST_PAD_NAME (realsink));
|
||||||
|
GST_UNLOCK (realsink);
|
||||||
|
GST_UNLOCK (realsrc);
|
||||||
|
return GST_PAD_LINK_WRONG_DIRECTION;
|
||||||
|
}
|
||||||
|
sink_was_linked:
|
||||||
|
{
|
||||||
|
/* we do not emit a warning in this case because unlinking cannot
|
||||||
|
* be made MT safe.*/
|
||||||
|
GST_UNLOCK (realsink);
|
||||||
|
GST_UNLOCK (realsrc);
|
||||||
|
return GST_PAD_LINK_WAS_LINKED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1166,6 +1287,8 @@ gst_pad_is_linked (GstPad * pad)
|
||||||
*
|
*
|
||||||
* Returns: A result code indicating if the connection worked or
|
* Returns: A result code indicating if the connection worked or
|
||||||
* what went wrong.
|
* what went wrong.
|
||||||
|
*
|
||||||
|
* MT Safe.
|
||||||
*/
|
*/
|
||||||
GstPadLinkReturn
|
GstPadLinkReturn
|
||||||
gst_pad_link_filtered (GstPad * srcpad, GstPad * sinkpad,
|
gst_pad_link_filtered (GstPad * srcpad, GstPad * sinkpad,
|
||||||
|
@ -1174,72 +1297,17 @@ gst_pad_link_filtered (GstPad * srcpad, GstPad * sinkpad,
|
||||||
GstRealPad *realsrc, *realsink;
|
GstRealPad *realsrc, *realsink;
|
||||||
GstPadLinkReturn result;
|
GstPadLinkReturn result;
|
||||||
|
|
||||||
/* generic checks */
|
result = gst_pad_link_prepare_filtered (srcpad, sinkpad, &realsrc, &realsink,
|
||||||
g_return_val_if_fail (GST_IS_PAD (srcpad), GST_PAD_LINK_REFUSED);
|
filtercaps);
|
||||||
g_return_val_if_fail (GST_IS_PAD (sinkpad), GST_PAD_LINK_REFUSED);
|
|
||||||
|
|
||||||
GST_CAT_INFO (GST_CAT_PADS, "trying to link %s:%s and %s:%s",
|
if (result != GST_PAD_LINK_OK)
|
||||||
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
|
goto prepare_failed;
|
||||||
|
|
||||||
/* now we need to deal with the real/ghost stuff */
|
|
||||||
realsrc = GST_PAD_REALIZE (srcpad);
|
|
||||||
realsink = GST_PAD_REALIZE (sinkpad);
|
|
||||||
|
|
||||||
if ((GST_PAD (realsrc) != srcpad) || (GST_PAD (realsink) != sinkpad)) {
|
|
||||||
GST_CAT_INFO (GST_CAT_PADS, "*actually* linking %s:%s and %s:%s",
|
|
||||||
GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
|
|
||||||
}
|
|
||||||
|
|
||||||
g_return_val_if_fail (realsrc != NULL, GST_PAD_LINK_REFUSED);
|
|
||||||
g_return_val_if_fail (realsink != NULL, GST_PAD_LINK_REFUSED);
|
|
||||||
|
|
||||||
GST_LOCK (realsrc);
|
|
||||||
GST_LOCK (realsink);
|
|
||||||
|
|
||||||
/* FIXME: shouldn't we convert this to g_return_val_if_fail? */
|
|
||||||
if (GST_RPAD_PEER (realsrc) != NULL) {
|
|
||||||
GST_CAT_INFO (GST_CAT_PADS, "Real source pad %s:%s has a peer, failed",
|
|
||||||
GST_DEBUG_PAD_NAME (realsrc));
|
|
||||||
result = GST_PAD_LINK_REFUSED;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
if (GST_RPAD_PEER (realsink) != NULL) {
|
|
||||||
GST_CAT_INFO (GST_CAT_PADS, "Real sink pad %s:%s has a peer, failed",
|
|
||||||
GST_DEBUG_PAD_NAME (realsink));
|
|
||||||
result = GST_PAD_LINK_REFUSED;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GST_RPAD_DIRECTION (realsrc) != GST_PAD_SRC) {
|
|
||||||
GST_CAT_INFO (GST_CAT_PADS,
|
|
||||||
"Real src pad %s:%s is not a source pad, failed",
|
|
||||||
GST_DEBUG_PAD_NAME (realsrc));
|
|
||||||
result = GST_PAD_LINK_REFUSED;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
if (GST_RPAD_DIRECTION (realsink) != GST_PAD_SINK) {
|
|
||||||
GST_CAT_INFO (GST_CAT_PADS, "Real sink pad %s:%s is not a sink pad, failed",
|
|
||||||
GST_DEBUG_PAD_NAME (realsink));
|
|
||||||
result = GST_PAD_LINK_REFUSED;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
/* FIXME check pad caps for non-empty intersection */
|
|
||||||
|
|
||||||
/* update filter before calling the link functions */
|
|
||||||
if (filtercaps) {
|
|
||||||
GstCaps *filtercopy = gst_caps_copy (filtercaps);
|
|
||||||
|
|
||||||
filtercopy = gst_caps_ref (filtercopy);
|
|
||||||
|
|
||||||
GST_RPAD_APPFILTER (realsrc) = filtercopy;
|
|
||||||
GST_RPAD_APPFILTER (realsink) = filtercopy;
|
|
||||||
} else {
|
|
||||||
GST_RPAD_APPFILTER (realsrc) = NULL;
|
|
||||||
GST_RPAD_APPFILTER (realsink) = NULL;
|
|
||||||
}
|
|
||||||
GST_UNLOCK (realsrc);
|
|
||||||
GST_UNLOCK (realsink);
|
GST_UNLOCK (realsink);
|
||||||
|
GST_UNLOCK (realsrc);
|
||||||
|
|
||||||
|
/* FIXME released the locks here, concurrent thread might link
|
||||||
|
* something else. */
|
||||||
if (GST_RPAD_LINKFUNC (realsrc)) {
|
if (GST_RPAD_LINKFUNC (realsrc)) {
|
||||||
/* this one will call the peer link function */
|
/* this one will call the peer link function */
|
||||||
result =
|
result =
|
||||||
|
@ -1259,8 +1327,8 @@ gst_pad_link_filtered (GstPad * srcpad, GstPad * sinkpad,
|
||||||
GST_RPAD_PEER (realsrc) = GST_REAL_PAD (realsink);
|
GST_RPAD_PEER (realsrc) = GST_REAL_PAD (realsink);
|
||||||
GST_RPAD_PEER (realsink) = GST_REAL_PAD (realsrc);
|
GST_RPAD_PEER (realsink) = GST_REAL_PAD (realsrc);
|
||||||
|
|
||||||
GST_UNLOCK (realsrc);
|
|
||||||
GST_UNLOCK (realsink);
|
GST_UNLOCK (realsink);
|
||||||
|
GST_UNLOCK (realsrc);
|
||||||
|
|
||||||
/* fire off a signal to each of the pads telling them
|
/* fire off a signal to each of the pads telling them
|
||||||
* that they've been linked */
|
* that they've been linked */
|
||||||
|
@ -1281,17 +1349,15 @@ gst_pad_link_filtered (GstPad * srcpad, GstPad * sinkpad,
|
||||||
gst_caps_replace (&GST_RPAD_APPFILTER (realsink), NULL);
|
gst_caps_replace (&GST_RPAD_APPFILTER (realsink), NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_UNLOCK (realsrc);
|
|
||||||
GST_UNLOCK (realsink);
|
GST_UNLOCK (realsink);
|
||||||
|
GST_UNLOCK (realsrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
error:
|
prepare_failed:
|
||||||
GST_UNLOCK (realsrc);
|
{
|
||||||
GST_UNLOCK (realsink);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1363,17 +1429,18 @@ gst_pad_get_real_parent (GstPad * pad)
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
|
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
|
||||||
|
|
||||||
GST_LOCK (pad);
|
GST_PAD_REALIZE_AND_LOCK (pad, realpad, lost_ghostpad);
|
||||||
realpad = GST_PAD_REALIZE (pad);
|
|
||||||
if (pad != GST_PAD_CAST (realpad)) {
|
|
||||||
GST_LOCK (realpad);
|
|
||||||
GST_UNLOCK (pad);
|
|
||||||
}
|
|
||||||
element = GST_PAD_PARENT (realpad);
|
element = GST_PAD_PARENT (realpad);
|
||||||
|
if (element)
|
||||||
gst_object_ref (GST_OBJECT (element));
|
gst_object_ref (GST_OBJECT (element));
|
||||||
GST_UNLOCK (realpad);
|
GST_UNLOCK (realpad);
|
||||||
|
|
||||||
return element;
|
return element;
|
||||||
|
|
||||||
|
lost_ghostpad:
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME not MT safe */
|
/* FIXME not MT safe */
|
||||||
|
@ -1425,24 +1492,25 @@ GstPadLinkReturn
|
||||||
gst_pad_relink_filtered (GstPad * srcpad, GstPad * sinkpad,
|
gst_pad_relink_filtered (GstPad * srcpad, GstPad * sinkpad,
|
||||||
const GstCaps * filtercaps)
|
const GstCaps * filtercaps)
|
||||||
{
|
{
|
||||||
GstCaps *filtercopy;
|
GstRealPad *realsrc, *realsink;
|
||||||
|
GstPadLinkReturn result;
|
||||||
|
|
||||||
/* create copy with two refs */
|
result = gst_pad_link_prepare_filtered (srcpad, sinkpad, &realsrc, &realsink,
|
||||||
filtercopy = gst_caps_copy (filtercaps);
|
filtercaps);
|
||||||
filtercopy = gst_caps_ref (filtercopy);
|
|
||||||
|
|
||||||
/* probably check if intersection with new filter is ok */
|
if (result != GST_PAD_LINK_OK)
|
||||||
GST_LOCK (srcpad);
|
goto prepare_failed;
|
||||||
GST_LOCK (sinkpad);
|
|
||||||
gst_caps_replace (&GST_PAD_CAPS (srcpad), NULL);
|
|
||||||
gst_caps_replace (&GST_PAD_APPFILTER (srcpad), filtercopy);
|
|
||||||
|
|
||||||
gst_caps_replace (&GST_PAD_CAPS (sinkpad), NULL);
|
/* clear caps to force renegotiation */
|
||||||
gst_caps_replace (&GST_PAD_APPFILTER (sinkpad), filtercopy);
|
gst_caps_replace (&GST_PAD_CAPS (realsrc), NULL);
|
||||||
GST_UNLOCK (sinkpad);
|
gst_caps_replace (&GST_PAD_CAPS (realsink), NULL);
|
||||||
GST_UNLOCK (srcpad);
|
GST_UNLOCK (realsink);
|
||||||
|
GST_UNLOCK (realsrc);
|
||||||
|
|
||||||
return GST_PAD_LINK_OK;
|
return GST_PAD_LINK_OK;
|
||||||
|
|
||||||
|
prepare_failed:
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1619,16 +1687,61 @@ gst_pad_get_peer (GstPad * pad)
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
|
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
|
||||||
|
|
||||||
GST_LOCK (pad);
|
GST_PAD_REALIZE_AND_LOCK (pad, realpad, lost_ghostpad);
|
||||||
realpad = GST_PAD_REALIZE (pad);
|
|
||||||
if (pad != GST_PAD_CAST (realpad)) {
|
|
||||||
GST_LOCK (realpad);
|
|
||||||
GST_UNLOCK (pad);
|
|
||||||
}
|
|
||||||
result = GST_RPAD_PEER (realpad);
|
result = GST_RPAD_PEER (realpad);
|
||||||
|
if (result)
|
||||||
gst_object_ref (GST_OBJECT (result));
|
gst_object_ref (GST_OBJECT (result));
|
||||||
GST_UNLOCK (realpad);
|
GST_UNLOCK (realpad);
|
||||||
|
|
||||||
|
return GST_PAD_CAST (result);
|
||||||
|
|
||||||
|
lost_ghostpad:
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_pad_realize:
|
||||||
|
* @pad: a #GstPad to realize
|
||||||
|
*
|
||||||
|
* If the pad is a #GstRealPad, it is simply returned, else
|
||||||
|
* the #GstGhostPad will be dereffed to the real pad.
|
||||||
|
*
|
||||||
|
* After this function you always receive the real pad of
|
||||||
|
* the provided pad.
|
||||||
|
*
|
||||||
|
* This function unrefs the input pad and refs the result so
|
||||||
|
* that you can write constructs like:
|
||||||
|
*
|
||||||
|
* pad = gst_pad_realize(pad)
|
||||||
|
*
|
||||||
|
* without having to unref the old pad.
|
||||||
|
*
|
||||||
|
* Returns: the real #GstPad or NULL when an old reference to a
|
||||||
|
* ghostpad is used.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
|
*/
|
||||||
|
GstPad *
|
||||||
|
gst_pad_realize (GstPad * pad)
|
||||||
|
{
|
||||||
|
GstRealPad *result;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
|
||||||
|
|
||||||
|
GST_LOCK (pad);
|
||||||
|
result = GST_PAD_REALIZE (pad);
|
||||||
|
if (result && pad != GST_PAD_CAST (result)) {
|
||||||
|
gst_object_ref (GST_OBJECT (result));
|
||||||
|
GST_UNLOCK (pad);
|
||||||
|
/* no other thread could dispose this since we
|
||||||
|
* hold at least one ref */
|
||||||
|
gst_object_unref (GST_OBJECT (pad));
|
||||||
|
} else {
|
||||||
|
GST_UNLOCK (pad);
|
||||||
|
}
|
||||||
|
|
||||||
return GST_PAD_CAST (result);
|
return GST_PAD_CAST (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1641,13 +1754,16 @@ gst_pad_get_peer (GstPad * pad)
|
||||||
*
|
*
|
||||||
* Returns: the allowed #GstCaps of the pad link. Free the caps when
|
* Returns: the allowed #GstCaps of the pad link. Free the caps when
|
||||||
* you no longer need it.
|
* you no longer need it.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstCaps *
|
GstCaps *
|
||||||
gst_pad_get_allowed_caps (GstPad * pad)
|
gst_pad_get_allowed_caps (GstPad * pad)
|
||||||
{
|
{
|
||||||
const GstCaps *mycaps;
|
GstCaps *mycaps;
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
GstCaps *peercaps;
|
GstCaps *peercaps;
|
||||||
|
GstRealPad *peer;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_REAL_PAD (pad), NULL);
|
g_return_val_if_fail (GST_IS_REAL_PAD (pad), NULL);
|
||||||
|
|
||||||
|
@ -1655,15 +1771,25 @@ gst_pad_get_allowed_caps (GstPad * pad)
|
||||||
GST_DEBUG_PAD_NAME (pad));
|
GST_DEBUG_PAD_NAME (pad));
|
||||||
|
|
||||||
mycaps = gst_pad_get_caps (pad);
|
mycaps = gst_pad_get_caps (pad);
|
||||||
if (GST_RPAD_PEER (pad) == NULL) {
|
GST_LOCK (pad);
|
||||||
|
peer = GST_RPAD_PEER (pad);
|
||||||
|
if (peer == NULL) {
|
||||||
GST_CAT_DEBUG (GST_CAT_PROPERTIES, "%s:%s: no peer, returning own caps",
|
GST_CAT_DEBUG (GST_CAT_PROPERTIES, "%s:%s: no peer, returning own caps",
|
||||||
GST_DEBUG_PAD_NAME (pad));
|
GST_DEBUG_PAD_NAME (pad));
|
||||||
return gst_caps_copy (mycaps);
|
GST_UNLOCK (pad);
|
||||||
|
|
||||||
|
return mycaps;
|
||||||
|
} else {
|
||||||
|
gst_object_ref (GST_OBJECT (peer));
|
||||||
|
GST_UNLOCK (pad);
|
||||||
}
|
}
|
||||||
|
|
||||||
peercaps = gst_pad_get_caps (GST_PAD_PEER (pad));
|
peercaps = gst_pad_get_caps (GST_PAD_CAST (peer));
|
||||||
|
gst_object_unref (GST_OBJECT (peer));
|
||||||
|
|
||||||
caps = gst_caps_intersect (mycaps, peercaps);
|
caps = gst_caps_intersect (mycaps, peercaps);
|
||||||
gst_caps_unref (peercaps);
|
gst_caps_unref (peercaps);
|
||||||
|
gst_caps_unref (mycaps);
|
||||||
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CAPS, "allowed caps %" GST_PTR_FORMAT, caps);
|
GST_CAT_DEBUG (GST_CAT_CAPS, "allowed caps %" GST_PTR_FORMAT, caps);
|
||||||
|
|
||||||
|
@ -1705,23 +1831,26 @@ gst_pad_alloc_buffer (GstPad * pad, guint64 offset, gint size)
|
||||||
if (G_LIKELY ((bufferallocfunc = peer->bufferallocfunc) == NULL))
|
if (G_LIKELY ((bufferallocfunc = peer->bufferallocfunc) == NULL))
|
||||||
goto fallback;
|
goto fallback;
|
||||||
|
|
||||||
|
GST_UNLOCK (pad);
|
||||||
|
|
||||||
GST_CAT_DEBUG (GST_CAT_PADS,
|
GST_CAT_DEBUG (GST_CAT_PADS,
|
||||||
"calling bufferallocfunc &%s (@%p) of peer pad %s:%s",
|
"calling bufferallocfunc &%s (@%p) of peer pad %s:%s",
|
||||||
GST_DEBUG_FUNCPTR_NAME (bufferallocfunc),
|
GST_DEBUG_FUNCPTR_NAME (bufferallocfunc),
|
||||||
&bufferallocfunc, GST_DEBUG_PAD_NAME (peer));
|
&bufferallocfunc, GST_DEBUG_PAD_NAME (peer));
|
||||||
GST_UNLOCK (pad);
|
|
||||||
|
|
||||||
result = bufferallocfunc (GST_PAD (peer), offset, size, GST_PAD_CAPS (pad));
|
result =
|
||||||
|
bufferallocfunc (GST_PAD_CAST (peer), offset, size, GST_PAD_CAPS (pad));
|
||||||
|
|
||||||
if (result == NULL) {
|
if (G_UNLIKELY (result == NULL)) {
|
||||||
GST_LOCK (pad);
|
GST_LOCK (pad);
|
||||||
goto fallback;
|
goto fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
/* fallback case */
|
/* fallback case, allocate a buffer of our own, add pad caps. */
|
||||||
fallback:
|
fallback:
|
||||||
|
{
|
||||||
caps = GST_PAD_CAPS (pad);
|
caps = GST_PAD_CAPS (pad);
|
||||||
gst_caps_ref (caps);
|
gst_caps_ref (caps);
|
||||||
GST_UNLOCK (pad);
|
GST_UNLOCK (pad);
|
||||||
|
@ -1731,6 +1860,7 @@ fallback:
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1991,7 +2121,8 @@ gst_pad_push (GstPad * pad, GstBuffer * buffer)
|
||||||
GstPadChainFunction chainfunc;
|
GstPadChainFunction chainfunc;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_REAL_PAD (pad), GST_FLOW_ERROR);
|
g_return_val_if_fail (GST_IS_REAL_PAD (pad), GST_FLOW_ERROR);
|
||||||
g_return_val_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SRC, GST_FLOW_ERROR);
|
g_return_val_if_fail (GST_RPAD_DIRECTION (pad) == GST_PAD_SRC,
|
||||||
|
GST_FLOW_ERROR);
|
||||||
g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
|
g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
|
||||||
g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
|
g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
|
||||||
|
|
||||||
|
@ -2006,19 +2137,16 @@ gst_pad_push (GstPad * pad, GstBuffer * buffer)
|
||||||
if (G_UNLIKELY (!GST_RPAD_IS_ACTIVE (peer)))
|
if (G_UNLIKELY (!GST_RPAD_IS_ACTIVE (peer)))
|
||||||
goto not_active;
|
goto not_active;
|
||||||
|
|
||||||
gst_object_ref (GST_OBJECT (peer));
|
gst_object_ref (GST_OBJECT_CAST (peer));
|
||||||
GST_UNLOCK (pad);
|
GST_UNLOCK (pad);
|
||||||
|
|
||||||
GST_LOCK (peer);
|
/* NOTE: we read the peer chainfunc unlocked.
|
||||||
if (G_UNLIKELY ((chainfunc = peer->chainfunc) == NULL))
|
|
||||||
goto no_function;
|
|
||||||
|
|
||||||
/* NOTE: after this unlock the peer could change chainfunction,
|
|
||||||
* we cannot hold the lock for the peer so we might send
|
* we cannot hold the lock for the peer so we might send
|
||||||
* the data to the wrong function. This is not really a
|
* the data to the wrong function. This is not really a
|
||||||
* problem since functions are assigned at creation time
|
* problem since functions are assigned at creation time
|
||||||
* and don't change that often... */
|
* and don't change that often... */
|
||||||
GST_UNLOCK (peer);
|
if (G_UNLIKELY ((chainfunc = peer->chainfunc) == NULL))
|
||||||
|
goto no_function;
|
||||||
|
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
|
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
|
||||||
"calling chainfunction &%s of peer pad %s:%s",
|
"calling chainfunction &%s of peer pad %s:%s",
|
||||||
|
@ -2026,7 +2154,7 @@ gst_pad_push (GstPad * pad, GstBuffer * buffer)
|
||||||
|
|
||||||
ret = chainfunc (GST_PAD_CAST (peer), buffer);
|
ret = chainfunc (GST_PAD_CAST (peer), buffer);
|
||||||
|
|
||||||
gst_object_unref (GST_OBJECT (peer));
|
gst_object_unref (GST_OBJECT_CAST (peer));
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -2044,7 +2172,8 @@ no_function:
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pushing, but not chainhandler");
|
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pushing, but not chainhandler");
|
||||||
g_warning ("push on pad %s:%s but it has no chainhandler, file a bug.",
|
g_warning ("push on pad %s:%s but it has no chainhandler, file a bug.",
|
||||||
GST_DEBUG_PAD_NAME (peer));
|
GST_DEBUG_PAD_NAME (peer));
|
||||||
GST_UNLOCK_RETURN (peer, GST_FLOW_ERROR);
|
gst_object_unref (GST_OBJECT (peer));
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2067,7 +2196,7 @@ gst_pad_pull (GstPad * pad, GstBuffer ** buffer)
|
||||||
GstPadGetFunction getfunc;
|
GstPadGetFunction getfunc;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_REAL_PAD (pad), GST_FLOW_ERROR);
|
g_return_val_if_fail (GST_IS_REAL_PAD (pad), GST_FLOW_ERROR);
|
||||||
g_return_val_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SINK,
|
g_return_val_if_fail (GST_RPAD_DIRECTION (pad) == GST_PAD_SINK,
|
||||||
GST_FLOW_ERROR);
|
GST_FLOW_ERROR);
|
||||||
g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
|
g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
|
||||||
|
|
||||||
|
@ -2079,23 +2208,20 @@ gst_pad_pull (GstPad * pad, GstBuffer ** buffer)
|
||||||
if (G_UNLIKELY ((peer = GST_RPAD_PEER (pad)) == NULL))
|
if (G_UNLIKELY ((peer = GST_RPAD_PEER (pad)) == NULL))
|
||||||
goto not_connected;
|
goto not_connected;
|
||||||
|
|
||||||
gst_object_ref (GST_OBJECT (peer));
|
gst_object_ref (GST_OBJECT_CAST (peer));
|
||||||
GST_UNLOCK (pad);
|
GST_UNLOCK (pad);
|
||||||
|
|
||||||
GST_LOCK (peer);
|
/* see note in above function */
|
||||||
if (G_UNLIKELY ((getfunc = peer->getfunc) == NULL))
|
if (G_UNLIKELY ((getfunc = peer->getfunc) == NULL))
|
||||||
goto no_function;
|
goto no_function;
|
||||||
|
|
||||||
/* see note in above function */
|
|
||||||
GST_UNLOCK (peer);
|
|
||||||
|
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
|
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
|
||||||
"calling getfunc %s of peer pad %s:%s",
|
"calling getfunc %s of peer pad %s:%s",
|
||||||
GST_DEBUG_FUNCPTR_NAME (getfunc), GST_DEBUG_PAD_NAME (peer));
|
GST_DEBUG_FUNCPTR_NAME (getfunc), GST_DEBUG_PAD_NAME (peer));
|
||||||
|
|
||||||
ret = getfunc (GST_PAD_CAST (peer), buffer);
|
ret = getfunc (GST_PAD_CAST (peer), buffer);
|
||||||
|
|
||||||
gst_object_unref (GST_OBJECT (peer));
|
gst_object_unref (GST_OBJECT_CAST (peer));
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -2109,7 +2235,8 @@ no_function:
|
||||||
GST_ELEMENT_ERROR (GST_PAD_PARENT (pad), CORE, PAD, (NULL),
|
GST_ELEMENT_ERROR (GST_PAD_PARENT (pad), CORE, PAD, (NULL),
|
||||||
("pull on pad %s:%s but the peer pad %s:%s has no getfunc",
|
("pull on pad %s:%s but the peer pad %s:%s has no getfunc",
|
||||||
GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (peer)));
|
GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (peer)));
|
||||||
GST_UNLOCK_RETURN (peer, GST_FLOW_ERROR);
|
gst_object_unref (GST_OBJECT (peer));
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2135,7 +2262,7 @@ gst_pad_pull_range (GstPad * pad, guint64 offset, guint size,
|
||||||
GstPadGetRangeFunction getrangefunc;
|
GstPadGetRangeFunction getrangefunc;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_REAL_PAD (pad), GST_FLOW_ERROR);
|
g_return_val_if_fail (GST_IS_REAL_PAD (pad), GST_FLOW_ERROR);
|
||||||
g_return_val_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SINK,
|
g_return_val_if_fail (GST_RPAD_DIRECTION (pad) == GST_PAD_SINK,
|
||||||
GST_FLOW_ERROR);
|
GST_FLOW_ERROR);
|
||||||
g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
|
g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
|
||||||
|
|
||||||
|
@ -2147,23 +2274,20 @@ gst_pad_pull_range (GstPad * pad, guint64 offset, guint size,
|
||||||
if (G_UNLIKELY ((peer = GST_RPAD_PEER (pad)) == NULL))
|
if (G_UNLIKELY ((peer = GST_RPAD_PEER (pad)) == NULL))
|
||||||
goto not_connected;
|
goto not_connected;
|
||||||
|
|
||||||
gst_object_ref (GST_OBJECT (peer));
|
gst_object_ref (GST_OBJECT_CAST (peer));
|
||||||
GST_UNLOCK (pad);
|
GST_UNLOCK (pad);
|
||||||
|
|
||||||
GST_LOCK (peer);
|
/* see note in above function */
|
||||||
if (G_UNLIKELY ((getrangefunc = peer->getrangefunc) == NULL))
|
if (G_UNLIKELY ((getrangefunc = peer->getrangefunc) == NULL))
|
||||||
goto no_function;
|
goto no_function;
|
||||||
|
|
||||||
/* see note in above function */
|
|
||||||
GST_UNLOCK (peer);
|
|
||||||
|
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
|
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
|
||||||
"calling getrangefunc %s of peer pad %s:%s",
|
"calling getrangefunc %s of peer pad %s:%s",
|
||||||
GST_DEBUG_FUNCPTR_NAME (getrangefunc), GST_DEBUG_PAD_NAME (peer));
|
GST_DEBUG_FUNCPTR_NAME (getrangefunc), GST_DEBUG_PAD_NAME (peer));
|
||||||
|
|
||||||
ret = getrangefunc (GST_PAD_CAST (peer), offset, size, buffer);
|
ret = getrangefunc (GST_PAD_CAST (peer), offset, size, buffer);
|
||||||
|
|
||||||
gst_object_unref (GST_OBJECT (peer));
|
gst_object_unref (GST_OBJECT_CAST (peer));
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -2177,7 +2301,8 @@ no_function:
|
||||||
GST_ELEMENT_ERROR (GST_PAD_PARENT (pad), CORE, PAD, (NULL),
|
GST_ELEMENT_ERROR (GST_PAD_PARENT (pad), CORE, PAD, (NULL),
|
||||||
("pullrange on pad %s:%s but the peer pad %s:%s has no getrangefunction",
|
("pullrange on pad %s:%s but the peer pad %s:%s has no getrangefunction",
|
||||||
GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (peer)));
|
GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (peer)));
|
||||||
GST_UNLOCK_RETURN (peer, GST_FLOW_ERROR);
|
gst_object_unref (GST_OBJECT (peer));
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
|
|
10
gst/gstpad.h
10
gst/gstpad.h
|
@ -87,9 +87,11 @@ typedef struct _GstStaticPadTemplate GstStaticPadTemplate;
|
||||||
typedef struct _GstPadLink GstPadLink;
|
typedef struct _GstPadLink GstPadLink;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GST_PAD_LINK_NOSCHED = -3, /* pads cannot cooperate in scheduling */
|
GST_PAD_LINK_NOSCHED = -5, /* pads cannot cooperate in scheduling */
|
||||||
GST_PAD_LINK_NOFORMAT = -2, /* pads do not have common format */
|
GST_PAD_LINK_NOFORMAT = -4, /* pads do not have common format */
|
||||||
GST_PAD_LINK_REFUSED = -1, /* refused for some reason */
|
GST_PAD_LINK_REFUSED = -3, /* refused for some reason */
|
||||||
|
GST_PAD_LINK_WRONG_DIRECTION = -2, /* pads have wrong direction */
|
||||||
|
GST_PAD_LINK_WAS_LINKED = -1, /* pad was already linked */
|
||||||
GST_PAD_LINK_OK = 0, /* link ok */
|
GST_PAD_LINK_OK = 0, /* link ok */
|
||||||
} GstPadLinkReturn;
|
} GstPadLinkReturn;
|
||||||
|
|
||||||
|
@ -223,6 +225,7 @@ struct _GstRealPad {
|
||||||
GstPadEventMaskFunction eventmaskfunc;
|
GstPadEventMaskFunction eventmaskfunc;
|
||||||
|
|
||||||
GList *ghostpads;
|
GList *ghostpads;
|
||||||
|
guint32 ghostpads_cookie;
|
||||||
|
|
||||||
/* query/convert/formats functions */
|
/* query/convert/formats functions */
|
||||||
GstPadConvertFunction convertfunc;
|
GstPadConvertFunction convertfunc;
|
||||||
|
@ -458,6 +461,7 @@ gboolean gst_pad_unlink (GstPad *srcpad, GstPad *sinkpad);
|
||||||
gboolean gst_pad_is_linked (GstPad *pad);
|
gboolean gst_pad_is_linked (GstPad *pad);
|
||||||
|
|
||||||
GstPad* gst_pad_get_peer (GstPad *pad);
|
GstPad* gst_pad_get_peer (GstPad *pad);
|
||||||
|
GstPad* gst_pad_realize (GstPad *pad);
|
||||||
|
|
||||||
/* capsnego functions */
|
/* capsnego functions */
|
||||||
void gst_pad_set_getcaps_function (GstPad *pad, GstPadGetCapsFunction getcaps);
|
void gst_pad_set_getcaps_function (GstPad *pad, GstPadGetCapsFunction getcaps);
|
||||||
|
|
|
@ -133,6 +133,7 @@ gst_pipeline_init (GTypeInstance * instance, gpointer g_class)
|
||||||
gst_bus_set_sync_handler (pipeline->bus,
|
gst_bus_set_sync_handler (pipeline->bus,
|
||||||
(GstBusSyncHandler) pipeline_bus_handler, pipeline);
|
(GstBusSyncHandler) pipeline_bus_handler, pipeline);
|
||||||
pipeline->eosed = NULL;
|
pipeline->eosed = NULL;
|
||||||
|
/* we are our own manager */
|
||||||
GST_ELEMENT_MANAGER (pipeline) = pipeline;
|
GST_ELEMENT_MANAGER (pipeline) = pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,6 +145,10 @@ gst_pipeline_dispose (GObject * object)
|
||||||
g_assert (GST_IS_SCHEDULER (pipeline->scheduler));
|
g_assert (GST_IS_SCHEDULER (pipeline->scheduler));
|
||||||
|
|
||||||
gst_scheduler_reset (pipeline->scheduler);
|
gst_scheduler_reset (pipeline->scheduler);
|
||||||
|
gst_object_replace ((GstObject **) & pipeline->bus, NULL);
|
||||||
|
gst_object_replace ((GstObject **) & pipeline->scheduler, NULL);
|
||||||
|
gst_object_replace ((GstObject **) & pipeline->fixed_clock, NULL);
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,26 +170,27 @@ is_eos (GstPipeline * pipeline)
|
||||||
GList *eosed;
|
GList *eosed;
|
||||||
GstElementState state, pending;
|
GstElementState state, pending;
|
||||||
gboolean complete;
|
gboolean complete;
|
||||||
|
gchar *name;
|
||||||
|
|
||||||
complete = gst_element_get_state (element, &state, &pending, NULL);
|
complete = gst_element_get_state (element, &state, &pending, NULL);
|
||||||
|
name = gst_element_get_name (element);
|
||||||
|
|
||||||
if (!complete) {
|
if (!complete) {
|
||||||
GST_DEBUG ("element %s still performing state change",
|
GST_DEBUG ("element %s still performing state change", name);
|
||||||
gst_element_get_name (element));
|
|
||||||
result = FALSE;
|
result = FALSE;
|
||||||
done = TRUE;
|
done = TRUE;
|
||||||
break;
|
goto done;
|
||||||
} else if (state != GST_STATE_PLAYING) {
|
} else if (state != GST_STATE_PLAYING) {
|
||||||
GST_DEBUG ("element %s not playing %d %d",
|
GST_DEBUG ("element %s not playing %d %d", name, state, pending);
|
||||||
gst_element_get_name (element), GST_STATE (element),
|
goto done;
|
||||||
GST_STATE_PENDING (element));
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
eosed = g_list_find (pipeline->eosed, element);
|
eosed = g_list_find (pipeline->eosed, element);
|
||||||
if (!eosed) {
|
if (!eosed) {
|
||||||
result = FALSE;
|
result = FALSE;
|
||||||
done = TRUE;
|
done = TRUE;
|
||||||
}
|
}
|
||||||
|
done:
|
||||||
|
g_free (name);
|
||||||
gst_object_unref (GST_OBJECT (element));
|
gst_object_unref (GST_OBJECT (element));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -200,6 +206,7 @@ is_eos (GstPipeline * pipeline)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
gst_iterator_free (sinks);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +232,9 @@ pipeline_bus_handler (GstBus * bus, GstMessage * message,
|
||||||
}
|
}
|
||||||
/* we drop all EOS messages */
|
/* we drop all EOS messages */
|
||||||
result = GST_BUS_DROP;
|
result = GST_BUS_DROP;
|
||||||
|
gst_message_unref (message);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case GST_MESSAGE_ERROR:
|
case GST_MESSAGE_ERROR:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
744
gst/gstthread.c
744
gst/gstthread.c
|
@ -1,744 +0,0 @@
|
||||||
/* GStreamer
|
|
||||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
|
||||||
* 2000 Wim Taymans <wtay@chello.be>
|
|
||||||
* 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
|
||||||
*
|
|
||||||
* gstthread.c: Threaded container object
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Library General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Library General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Library General Public
|
|
||||||
* License along with this library; if not, write to the
|
|
||||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
||||||
* Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "gst_private.h"
|
|
||||||
|
|
||||||
#include "gstthread.h"
|
|
||||||
#include "gstmarshal.h"
|
|
||||||
#include "gstscheduler.h"
|
|
||||||
#include "gstinfo.h"
|
|
||||||
|
|
||||||
#define GST_CAT_DEFAULT GST_CAT_THREAD
|
|
||||||
#define STACK_SIZE 0x200000
|
|
||||||
|
|
||||||
static GstElementDetails gst_thread_details =
|
|
||||||
GST_ELEMENT_DETAILS ("Threaded container",
|
|
||||||
"Generic/Bin",
|
|
||||||
"Container that creates/manages a thread",
|
|
||||||
"Erik Walthinsen <omega@cse.ogi.edu>, "
|
|
||||||
"Benjamin Otte <in7y118@informatik.uni-hamburg.de"
|
|
||||||
"Wim Taymans <wim@fluendo.com");
|
|
||||||
|
|
||||||
/* Thread signals and args */
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
SHUTDOWN,
|
|
||||||
/* FILL ME */
|
|
||||||
LAST_SIGNAL
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
SPINUP = 0,
|
|
||||||
STATECHANGE,
|
|
||||||
STARTUP
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
ARG_0,
|
|
||||||
ARG_PRIORITY
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static void gst_thread_base_init (gpointer g_class);
|
|
||||||
static void gst_thread_class_init (gpointer g_class, gpointer class_data);
|
|
||||||
static void gst_thread_init (GTypeInstance * instance, gpointer g_class);
|
|
||||||
|
|
||||||
static void gst_thread_dispose (GObject * object);
|
|
||||||
|
|
||||||
static void gst_thread_set_property (GObject * object, guint prop_id,
|
|
||||||
const GValue * value, GParamSpec * pspec);
|
|
||||||
static void gst_thread_get_property (GObject * object, guint prop_id,
|
|
||||||
GValue * value, GParamSpec * pspec);
|
|
||||||
static GstElementStateReturn gst_thread_change_state (GstElement * element);
|
|
||||||
static void gst_thread_child_state_change (GstBin * bin,
|
|
||||||
GstElementState oldstate, GstElementState newstate, GstElement * element);
|
|
||||||
|
|
||||||
static void gst_thread_sync (GstThread * thread, gboolean is_self);
|
|
||||||
|
|
||||||
#ifndef GST_DISABLE_LOADSAVE
|
|
||||||
static xmlNodePtr gst_thread_save_thyself (GstObject * object,
|
|
||||||
xmlNodePtr parent);
|
|
||||||
static void gst_thread_restore_thyself (GstObject * object, xmlNodePtr self);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void *gst_thread_main_loop (void *arg);
|
|
||||||
|
|
||||||
#define GST_TYPE_THREAD_PRIORITY (gst_thread_priority_get_type())
|
|
||||||
static GType
|
|
||||||
gst_thread_priority_get_type (void)
|
|
||||||
{
|
|
||||||
static GType thread_priority_type = 0;
|
|
||||||
static GEnumValue thread_priority[] = {
|
|
||||||
{G_THREAD_PRIORITY_LOW, "LOW", "Low Priority Scheduling"},
|
|
||||||
{G_THREAD_PRIORITY_NORMAL, "NORMAL", "Normal Scheduling"},
|
|
||||||
{G_THREAD_PRIORITY_HIGH, "HIGH", "High Priority Scheduling"},
|
|
||||||
{G_THREAD_PRIORITY_URGENT, "URGENT", "Urgent Scheduling"},
|
|
||||||
{0, NULL, NULL},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!thread_priority_type) {
|
|
||||||
thread_priority_type =
|
|
||||||
g_enum_register_static ("GstThreadPriority", thread_priority);
|
|
||||||
}
|
|
||||||
return thread_priority_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstBinClass *parent_class = NULL;
|
|
||||||
static guint gst_thread_signals[LAST_SIGNAL] = { 0 };
|
|
||||||
GPrivate *gst_thread_current;
|
|
||||||
|
|
||||||
GType
|
|
||||||
gst_thread_get_type (void)
|
|
||||||
{
|
|
||||||
static GType thread_type = 0;
|
|
||||||
|
|
||||||
if (!thread_type) {
|
|
||||||
static const GTypeInfo thread_info = {
|
|
||||||
sizeof (GstThreadClass),
|
|
||||||
gst_thread_base_init,
|
|
||||||
NULL,
|
|
||||||
gst_thread_class_init,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
sizeof (GstThread),
|
|
||||||
0,
|
|
||||||
gst_thread_init,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
thread_type = g_type_register_static (GST_TYPE_BIN, "GstThread",
|
|
||||||
&thread_info, 0);
|
|
||||||
}
|
|
||||||
return thread_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_thread_base_init (gpointer g_class)
|
|
||||||
{
|
|
||||||
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
|
|
||||||
|
|
||||||
gst_element_class_set_details (gstelement_class, &gst_thread_details);
|
|
||||||
}
|
|
||||||
static void
|
|
||||||
do_nothing (gpointer hi)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
static void
|
|
||||||
gst_thread_class_init (gpointer g_class, gpointer class_data)
|
|
||||||
{
|
|
||||||
GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
|
|
||||||
|
|
||||||
#ifndef GST_DISABLE_LOADSAVE
|
|
||||||
GstObjectClass *gstobject_class = GST_OBJECT_CLASS (g_class);
|
|
||||||
#endif
|
|
||||||
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
|
|
||||||
GstBinClass *gstbin_class = GST_BIN_CLASS (g_class);
|
|
||||||
GstThreadClass *klass = GST_THREAD_CLASS (g_class);
|
|
||||||
|
|
||||||
/* setup gst_thread_current */
|
|
||||||
gst_thread_current = g_private_new (do_nothing);
|
|
||||||
|
|
||||||
parent_class = g_type_class_peek_parent (g_class);
|
|
||||||
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PRIORITY,
|
|
||||||
g_param_spec_enum ("priority", "Scheduling Policy",
|
|
||||||
"The scheduling priority of the thread", GST_TYPE_THREAD_PRIORITY,
|
|
||||||
G_THREAD_PRIORITY_NORMAL, G_PARAM_READWRITE));
|
|
||||||
|
|
||||||
gst_thread_signals[SHUTDOWN] =
|
|
||||||
g_signal_new ("shutdown", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
|
|
||||||
G_STRUCT_OFFSET (GstThreadClass, shutdown), NULL, NULL,
|
|
||||||
gst_marshal_VOID__VOID, G_TYPE_NONE, 0);
|
|
||||||
|
|
||||||
gobject_class->dispose = gst_thread_dispose;
|
|
||||||
|
|
||||||
#ifndef GST_DISABLE_LOADSAVE
|
|
||||||
gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_thread_save_thyself);
|
|
||||||
gstobject_class->restore_thyself =
|
|
||||||
GST_DEBUG_FUNCPTR (gst_thread_restore_thyself);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_thread_change_state);
|
|
||||||
|
|
||||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_thread_set_property);
|
|
||||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_thread_get_property);
|
|
||||||
|
|
||||||
gstbin_class->child_state_change =
|
|
||||||
GST_DEBUG_FUNCPTR (gst_thread_child_state_change);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_thread_init (GTypeInstance * instance, gpointer g_class)
|
|
||||||
{
|
|
||||||
GstScheduler *scheduler;
|
|
||||||
GstThread *thread = GST_THREAD (instance);
|
|
||||||
|
|
||||||
GST_DEBUG ("initializing thread");
|
|
||||||
|
|
||||||
/* threads are managing bins and iterate themselves */
|
|
||||||
/* CR1: the GstBin code checks these flags */
|
|
||||||
GST_FLAG_SET (thread, GST_BIN_FLAG_MANAGER);
|
|
||||||
GST_FLAG_SET (thread, GST_BIN_SELF_SCHEDULABLE);
|
|
||||||
|
|
||||||
scheduler = gst_scheduler_factory_make (NULL, GST_ELEMENT (thread));
|
|
||||||
g_assert (scheduler);
|
|
||||||
|
|
||||||
thread->lock = g_mutex_new ();
|
|
||||||
thread->cond = g_cond_new ();
|
|
||||||
thread->iterate_lock = g_mutex_new ();
|
|
||||||
|
|
||||||
thread->thread_id = (GThread *) NULL; /* set in NULL -> READY */
|
|
||||||
thread->priority = G_THREAD_PRIORITY_NORMAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_thread_dispose (GObject * object)
|
|
||||||
{
|
|
||||||
GstThread *thread = GST_THREAD (object);
|
|
||||||
|
|
||||||
GST_CAT_DEBUG (GST_CAT_REFCOUNTING, "GstThread: dispose");
|
|
||||||
|
|
||||||
/* if we get here, the thread is really stopped as it has released
|
|
||||||
* the last refcount to the thread object, so we can safely free the
|
|
||||||
* mutex and cond vars */
|
|
||||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
|
||||||
|
|
||||||
g_assert (GST_STATE (thread) == GST_STATE_NULL);
|
|
||||||
|
|
||||||
GST_CAT_DEBUG (GST_CAT_REFCOUNTING, "GstThread: dispose, freeing locks");
|
|
||||||
|
|
||||||
g_mutex_free (thread->lock);
|
|
||||||
g_cond_free (thread->cond);
|
|
||||||
g_mutex_free (thread->iterate_lock);
|
|
||||||
|
|
||||||
gst_object_replace ((GstObject **) & GST_ELEMENT_SCHED (thread), NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_thread_set_priority:
|
|
||||||
* @thread: the thread to change
|
|
||||||
* @priority: the new priority for the thread
|
|
||||||
*
|
|
||||||
* change the thread's priority
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
gst_thread_set_priority (GstThread * thread, GThreadPriority priority)
|
|
||||||
{
|
|
||||||
g_return_if_fail (GST_IS_THREAD (thread));
|
|
||||||
|
|
||||||
thread->priority = priority;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_thread_set_property (GObject * object, guint prop_id, const GValue * value,
|
|
||||||
GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
GstThread *thread;
|
|
||||||
|
|
||||||
thread = GST_THREAD (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case ARG_PRIORITY:
|
|
||||||
thread->priority = g_value_get_enum (value);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_thread_get_property (GObject * object, guint prop_id, GValue * value,
|
|
||||||
GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
GstThread *thread;
|
|
||||||
|
|
||||||
thread = GST_THREAD (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case ARG_PRIORITY:
|
|
||||||
g_value_set_enum (value, thread->priority);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_thread_new:
|
|
||||||
* @name: the name of the thread
|
|
||||||
*
|
|
||||||
* Create a new thread with the given name.
|
|
||||||
*
|
|
||||||
* Returns: The new thread
|
|
||||||
*/
|
|
||||||
GstElement *
|
|
||||||
gst_thread_new (const gchar * name)
|
|
||||||
{
|
|
||||||
return gst_element_factory_make ("thread", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_thread_get_current:
|
|
||||||
*
|
|
||||||
* Gets the current GstThread.
|
|
||||||
*
|
|
||||||
* Returns: The current GstThread or NULL if you are not running inside a
|
|
||||||
* #GstThread.
|
|
||||||
*/
|
|
||||||
GstThread *
|
|
||||||
gst_thread_get_current (void)
|
|
||||||
{
|
|
||||||
return (GstThread *) g_private_get (gst_thread_current);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
gst_thread_release_children_locks (GstThread * thread)
|
|
||||||
{
|
|
||||||
GstRealPad *peer = NULL;
|
|
||||||
GstElement *peerelement;
|
|
||||||
GList *elements = (GList *) gst_bin_get_list (GST_BIN (thread));
|
|
||||||
|
|
||||||
while (elements) {
|
|
||||||
GstElement *element = GST_ELEMENT (elements->data);
|
|
||||||
GList *pads;
|
|
||||||
|
|
||||||
g_assert (element);
|
|
||||||
GST_DEBUG_OBJECT (thread, "waking element \"%s\"",
|
|
||||||
GST_ELEMENT_NAME (element));
|
|
||||||
elements = g_list_next (elements);
|
|
||||||
|
|
||||||
if (!gst_element_release_locks (element))
|
|
||||||
g_warning ("element %s could not release locks",
|
|
||||||
GST_ELEMENT_NAME (element));
|
|
||||||
|
|
||||||
pads = GST_ELEMENT_PADS (element);
|
|
||||||
|
|
||||||
while (pads) {
|
|
||||||
if (GST_PAD_PEER (pads->data)) {
|
|
||||||
peer = GST_REAL_PAD (GST_PAD_PEER (pads->data));
|
|
||||||
pads = g_list_next (pads);
|
|
||||||
} else {
|
|
||||||
pads = g_list_next (pads);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!peer)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
peerelement = GST_PAD_PARENT (peer);
|
|
||||||
if (!peerelement)
|
|
||||||
continue; /* FIXME: deal with case where there's no peer */
|
|
||||||
|
|
||||||
if (GST_ELEMENT_SCHED (peerelement) != GST_ELEMENT_SCHED (thread)) {
|
|
||||||
GST_LOG_OBJECT (thread, "element \"%s\" has pad cross sched boundary",
|
|
||||||
GST_ELEMENT_NAME (element));
|
|
||||||
GST_LOG_OBJECT (thread, "waking element \"%s\"",
|
|
||||||
GST_ELEMENT_NAME (peerelement));
|
|
||||||
if (!gst_element_release_locks (peerelement))
|
|
||||||
g_warning ("element %s could not release locks",
|
|
||||||
GST_ELEMENT_NAME (peerelement));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* sync the main thread, if there is one and makes sure that the thread
|
|
||||||
* is not spinning and in the waiting state. We can only do this if
|
|
||||||
* this function is not called from the thread itself.
|
|
||||||
*
|
|
||||||
* This function should be called with the thread lock held.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
gst_thread_sync (GstThread * thread, gboolean is_self)
|
|
||||||
{
|
|
||||||
if (thread->thread_id == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* need to stop spinning in any case */
|
|
||||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
|
||||||
|
|
||||||
if (is_self) {
|
|
||||||
/* we're trying to sync ourself. Not much we can do here but hope
|
|
||||||
* that the thread will stop spinning and end up in the waiting
|
|
||||||
* state */
|
|
||||||
GST_DEBUG_OBJECT (thread, "syncing itself");
|
|
||||||
} else {
|
|
||||||
GST_DEBUG_OBJECT (thread, "syncing thread, grabbing lock");
|
|
||||||
/* another thread is trying to sync us. The strategy is to
|
|
||||||
* repeadetly unlock the element locks until the thread is
|
|
||||||
* blocking in the waiting state. We use a timeout because
|
|
||||||
* unlocking all of the children at the same time is not
|
|
||||||
* atomic and might fail. */
|
|
||||||
while (!GST_FLAG_IS_SET (thread, GST_THREAD_STATE_WAITING)) {
|
|
||||||
GTimeVal tv;
|
|
||||||
|
|
||||||
GST_LOG_OBJECT (thread, "syncing thread...");
|
|
||||||
|
|
||||||
/* release child locks */
|
|
||||||
gst_thread_release_children_locks (thread);
|
|
||||||
g_get_current_time (&tv);
|
|
||||||
g_time_val_add (&tv, 1000); /* wait a millisecond to sync the thread */
|
|
||||||
GST_DEBUG_OBJECT (thread, "wait");
|
|
||||||
g_cond_timed_wait (thread->cond, thread->lock, &tv);
|
|
||||||
}
|
|
||||||
GST_LOG_OBJECT (thread, "caught thread");
|
|
||||||
/* at this point we should be waiting */
|
|
||||||
g_assert (GST_FLAG_IS_SET (thread, GST_THREAD_STATE_WAITING));
|
|
||||||
}
|
|
||||||
g_assert (!GST_FLAG_IS_SET (thread, GST_THREAD_STATE_SPINNING));
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstElementStateReturn
|
|
||||||
gst_thread_change_state (GstElement * element)
|
|
||||||
{
|
|
||||||
GstThread *thread;
|
|
||||||
GstElementStateReturn ret;
|
|
||||||
gint transition;
|
|
||||||
gboolean is_self;
|
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_THREAD (element), GST_STATE_FAILURE);
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (element, "changing state from %s to %s",
|
|
||||||
gst_element_state_get_name (GST_STATE (element)),
|
|
||||||
gst_element_state_get_name (GST_STATE_PENDING (element)));
|
|
||||||
|
|
||||||
thread = GST_THREAD (element);
|
|
||||||
|
|
||||||
/* boolean to check if we called the state change in the same thread as
|
|
||||||
* the iterate thread */
|
|
||||||
is_self = (thread == gst_thread_get_current ());
|
|
||||||
|
|
||||||
GST_LOG_OBJECT (thread, "grabbing lock");
|
|
||||||
g_mutex_lock (thread->lock);
|
|
||||||
|
|
||||||
gst_thread_sync (thread, is_self);
|
|
||||||
|
|
||||||
/* no iteration is allowed during this state change because an iteration
|
|
||||||
* can cause another state change conflicting with this one */
|
|
||||||
/* do not try to grab the lock if this method is called from the
|
|
||||||
* same thread as the iterate thread, the lock might be held and we
|
|
||||||
* might deadlock */
|
|
||||||
if (!is_self)
|
|
||||||
g_mutex_lock (thread->iterate_lock);
|
|
||||||
|
|
||||||
transition = GST_STATE_TRANSITION (element);
|
|
||||||
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_NULL_TO_READY:
|
|
||||||
/* create the thread */
|
|
||||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_REAPING);
|
|
||||||
GST_LOG_OBJECT (element, "grabbing lock");
|
|
||||||
thread->thread_id = g_thread_create_full (gst_thread_main_loop,
|
|
||||||
thread, STACK_SIZE, FALSE, TRUE, thread->priority, NULL);
|
|
||||||
if (!thread->thread_id) {
|
|
||||||
GST_ERROR_OBJECT (element, "g_thread_create_full failed");
|
|
||||||
goto error_out;
|
|
||||||
}
|
|
||||||
GST_LOG_OBJECT (element, "GThread created");
|
|
||||||
|
|
||||||
/* wait for it to 'spin up' */
|
|
||||||
g_cond_wait (thread->cond, thread->lock);
|
|
||||||
break;
|
|
||||||
case GST_STATE_READY_TO_PAUSED:
|
|
||||||
break;
|
|
||||||
case GST_STATE_PAUSED_TO_PLAYING:
|
|
||||||
{
|
|
||||||
/* FIXME: recurse into sub-bins */
|
|
||||||
GList *elements = (GList *) gst_bin_get_list (GST_BIN (thread));
|
|
||||||
|
|
||||||
while (elements) {
|
|
||||||
gst_element_enable_threadsafe_properties ((GstElement *) elements->
|
|
||||||
data);
|
|
||||||
elements = g_list_next (elements);
|
|
||||||
}
|
|
||||||
/* reset self to spinning */
|
|
||||||
GST_FLAG_SET (thread, GST_THREAD_STATE_SPINNING);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case GST_STATE_PLAYING_TO_PAUSED:
|
|
||||||
{
|
|
||||||
GList *elements;
|
|
||||||
|
|
||||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
|
||||||
|
|
||||||
elements = (GList *) gst_bin_get_list (GST_BIN (thread));
|
|
||||||
|
|
||||||
while (elements) {
|
|
||||||
gst_element_disable_threadsafe_properties ((GstElement *) elements->
|
|
||||||
data);
|
|
||||||
elements = g_list_next (elements);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case GST_STATE_PAUSED_TO_READY:
|
|
||||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
|
||||||
break;
|
|
||||||
case GST_STATE_READY_TO_NULL:
|
|
||||||
/* we can't join the threads here, because this could have been triggered
|
|
||||||
by ourself (ouch) */
|
|
||||||
GST_LOG_OBJECT (thread, "destroying GThread %p", thread->thread_id);
|
|
||||||
GST_FLAG_SET (thread, GST_THREAD_STATE_REAPING);
|
|
||||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
|
||||||
/* thread was already gone */
|
|
||||||
if (thread->thread_id != NULL) {
|
|
||||||
thread->thread_id = NULL;
|
|
||||||
if (is_self) {
|
|
||||||
/* or should we continue? */
|
|
||||||
GST_LOG_OBJECT (thread,
|
|
||||||
"Thread %s is destroying itself. Function call will not return!",
|
|
||||||
GST_ELEMENT_NAME (thread));
|
|
||||||
gst_scheduler_reset (GST_ELEMENT_SCHED (thread));
|
|
||||||
|
|
||||||
/* unlock and signal - we are out */
|
|
||||||
GST_DEBUG_OBJECT (thread, "signal");
|
|
||||||
g_cond_signal (thread->cond);
|
|
||||||
GST_DEBUG_OBJECT (thread, "unlock");
|
|
||||||
g_mutex_unlock (thread->lock);
|
|
||||||
|
|
||||||
GST_INFO_OBJECT (thread, "GThread %p is exiting", g_thread_self ());
|
|
||||||
|
|
||||||
g_signal_emit (G_OBJECT (thread), gst_thread_signals[SHUTDOWN], 0);
|
|
||||||
|
|
||||||
g_thread_exit (NULL);
|
|
||||||
return GST_STATE_SUCCESS;
|
|
||||||
} else {
|
|
||||||
/* now wait for the thread to destroy itself */
|
|
||||||
GST_DEBUG_OBJECT (thread, "signal");
|
|
||||||
g_cond_signal (thread->cond);
|
|
||||||
GST_DEBUG_OBJECT (thread, "wait");
|
|
||||||
g_cond_wait (thread->cond, thread->lock);
|
|
||||||
GST_DEBUG_OBJECT (thread, "done");
|
|
||||||
/* it should be dead now */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
GST_LOG_OBJECT (thread, "unlocking lock");
|
|
||||||
g_mutex_unlock (thread->lock);
|
|
||||||
|
|
||||||
if (GST_ELEMENT_CLASS (parent_class)->change_state) {
|
|
||||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT (thread));
|
|
||||||
} else {
|
|
||||||
ret = GST_STATE_SUCCESS;
|
|
||||||
}
|
|
||||||
if (!is_self)
|
|
||||||
g_mutex_unlock (thread->iterate_lock);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
error_out:
|
|
||||||
GST_CAT_DEBUG (GST_CAT_STATES, "changing state from %s to %s failed for %s",
|
|
||||||
gst_element_state_get_name (GST_STATE (element)),
|
|
||||||
gst_element_state_get_name (GST_STATE_PENDING (element)),
|
|
||||||
GST_ELEMENT_NAME (element));
|
|
||||||
|
|
||||||
g_mutex_unlock (thread->lock);
|
|
||||||
|
|
||||||
if (!is_self)
|
|
||||||
g_mutex_unlock (thread->iterate_lock);
|
|
||||||
|
|
||||||
return GST_STATE_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* When a child changes its state the thread might have to start.
|
|
||||||
*
|
|
||||||
* When we are in the thread context we set the spinning flag.
|
|
||||||
* When we are not in the thread context, we grab the lock. The
|
|
||||||
* thread can then only be in the waiting or spinning state. If it's
|
|
||||||
* waiting we signal it to start. If it was spinning, we let it spin.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
gst_thread_child_state_change (GstBin * bin, GstElementState oldstate,
|
|
||||||
GstElementState newstate, GstElement * element)
|
|
||||||
{
|
|
||||||
GstThread *thread = GST_THREAD (bin);
|
|
||||||
gboolean is_self;
|
|
||||||
GstThread *current;
|
|
||||||
|
|
||||||
current = gst_thread_get_current ();
|
|
||||||
|
|
||||||
is_self = (current == thread);
|
|
||||||
|
|
||||||
GST_LOG_OBJECT (bin, "(from thread %s) child %s changed state from %s to %s",
|
|
||||||
current ? GST_ELEMENT_NAME (current) :
|
|
||||||
"(none)", GST_ELEMENT_NAME (element),
|
|
||||||
gst_element_state_get_name (oldstate),
|
|
||||||
gst_element_state_get_name (newstate));
|
|
||||||
|
|
||||||
if (parent_class->child_state_change)
|
|
||||||
parent_class->child_state_change (bin, oldstate, newstate, element);
|
|
||||||
|
|
||||||
/* see if we have to wake up the thread now. */
|
|
||||||
if (is_self) {
|
|
||||||
GST_LOG_OBJECT (element, "we are in the thread context");
|
|
||||||
/* we are the thread, set the spinning flag so that we start spinning
|
|
||||||
* next time */
|
|
||||||
if (newstate == GST_STATE_PLAYING) {
|
|
||||||
GST_FLAG_SET (thread, GST_THREAD_STATE_SPINNING);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
g_mutex_lock (thread->lock);
|
|
||||||
/* thread is now spinning or waiting after grabbing the lock */
|
|
||||||
if (newstate == GST_STATE_PLAYING) {
|
|
||||||
if (!GST_FLAG_IS_SET (thread, GST_THREAD_STATE_WAITING)) {
|
|
||||||
/* its spinning, that's not really a problem, it will
|
|
||||||
* continue to do so */
|
|
||||||
GST_LOG_OBJECT (element, "thread is playing");
|
|
||||||
} else {
|
|
||||||
/* waiting, set spinning flag and trigger restart. */
|
|
||||||
GST_LOG_OBJECT (element, "signal playing");
|
|
||||||
GST_FLAG_SET (thread, GST_THREAD_STATE_SPINNING);
|
|
||||||
g_cond_signal (GST_THREAD (bin)->cond);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g_mutex_unlock (thread->lock);
|
|
||||||
}
|
|
||||||
GST_LOG_OBJECT (element, "done child state change");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_thread_main_loop:
|
|
||||||
* @arg: the thread to start
|
|
||||||
*
|
|
||||||
* The main loop of the thread. The thread will iterate
|
|
||||||
* while the state is GST_THREAD_STATE_SPINNING.
|
|
||||||
*/
|
|
||||||
static void *
|
|
||||||
gst_thread_main_loop (void *arg)
|
|
||||||
{
|
|
||||||
GstThread *thread = NULL;
|
|
||||||
GstElement *element = NULL;
|
|
||||||
GstScheduler *sched;
|
|
||||||
|
|
||||||
thread = GST_THREAD (arg);
|
|
||||||
GST_LOG_OBJECT (element, "grabbing lock");
|
|
||||||
g_mutex_lock (thread->lock);
|
|
||||||
element = GST_ELEMENT (arg);
|
|
||||||
GST_LOG_OBJECT (thread, "Started main loop");
|
|
||||||
|
|
||||||
/* initialize gst_thread_current */
|
|
||||||
g_private_set (gst_thread_current, thread);
|
|
||||||
|
|
||||||
/* set up the element's scheduler */
|
|
||||||
gst_scheduler_setup (GST_ELEMENT_SCHED (thread));
|
|
||||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_REAPING);
|
|
||||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_WAITING);
|
|
||||||
|
|
||||||
/* signals the startup of the thread */
|
|
||||||
GST_LOG_OBJECT (element, "signal");
|
|
||||||
g_cond_signal (thread->cond);
|
|
||||||
GST_LOG_OBJECT (element, "unlocking lock");
|
|
||||||
|
|
||||||
gst_object_ref (GST_OBJECT (thread));
|
|
||||||
/* as long as we're not dying we can continue */
|
|
||||||
while (!(GST_FLAG_IS_SET (thread, GST_THREAD_STATE_REAPING))) {
|
|
||||||
/* in the playing state we need to do something special */
|
|
||||||
if (GST_STATE (thread) == GST_STATE_PLAYING) {
|
|
||||||
GST_LOG_OBJECT (thread, "starting to iterate");
|
|
||||||
/* continue iteration while spinning */
|
|
||||||
while (GST_FLAG_IS_SET (thread, GST_THREAD_STATE_SPINNING)) {
|
|
||||||
gboolean status;
|
|
||||||
|
|
||||||
g_mutex_unlock (thread->lock);
|
|
||||||
g_mutex_lock (thread->iterate_lock);
|
|
||||||
status = gst_bin_iterate (GST_BIN (thread));
|
|
||||||
g_mutex_unlock (thread->iterate_lock);
|
|
||||||
g_mutex_lock (thread->lock);
|
|
||||||
|
|
||||||
if (!status) {
|
|
||||||
GST_DEBUG_OBJECT (thread, "iterate returned false");
|
|
||||||
if (GST_STATE (thread) != GST_STATE_PLAYING) {
|
|
||||||
GST_DEBUG_OBJECT (thread,
|
|
||||||
"stopping spinning as state is not playing");
|
|
||||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* if we hold the last refcount, the app unreffed the
|
|
||||||
* thread and we should stop ASAP */
|
|
||||||
if (G_OBJECT (thread)->ref_count == 1) {
|
|
||||||
GST_DEBUG_OBJECT (thread, "reaping as refcount is only 1");
|
|
||||||
GST_FLAG_SET (thread, GST_THREAD_STATE_REAPING);
|
|
||||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* do not try to sync when we are REAPING */
|
|
||||||
if (!(GST_FLAG_IS_SET (thread, GST_THREAD_STATE_REAPING))) {
|
|
||||||
/* sync section */
|
|
||||||
GST_LOG_OBJECT (thread, "entering sync");
|
|
||||||
GST_DEBUG_OBJECT (thread, "signal");
|
|
||||||
g_cond_signal (thread->cond);
|
|
||||||
GST_DEBUG_OBJECT (thread, "wait");
|
|
||||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
|
||||||
GST_FLAG_SET (thread, GST_THREAD_STATE_WAITING);
|
|
||||||
g_cond_wait (thread->cond, thread->lock);
|
|
||||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_WAITING);
|
|
||||||
GST_LOG_OBJECT (thread, "wait done");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GST_LOG_OBJECT (thread, "unlocking lock");
|
|
||||||
thread->thread_id = NULL;
|
|
||||||
g_mutex_unlock (thread->lock);
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
if (sched)
|
|
||||||
gst_scheduler_reset (sched);
|
|
||||||
|
|
||||||
g_signal_emit (G_OBJECT (thread), gst_thread_signals[SHUTDOWN], 0);
|
|
||||||
|
|
||||||
/* signal - we are out */
|
|
||||||
GST_LOG_OBJECT (thread, "Thread %p exits main loop", g_thread_self ());
|
|
||||||
g_cond_signal (thread->cond);
|
|
||||||
gst_object_unref (GST_OBJECT (thread));
|
|
||||||
/* don't assume the GstThread object exists anymore now */
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef GST_DISABLE_LOADSAVE
|
|
||||||
static xmlNodePtr
|
|
||||||
gst_thread_save_thyself (GstObject * object, xmlNodePtr self)
|
|
||||||
{
|
|
||||||
if (GST_OBJECT_CLASS (parent_class)->save_thyself)
|
|
||||||
GST_OBJECT_CLASS (parent_class)->save_thyself (object, self);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_thread_restore_thyself (GstObject * object, xmlNodePtr self)
|
|
||||||
{
|
|
||||||
GST_LOG_OBJECT (object, "restoring");
|
|
||||||
|
|
||||||
if (GST_OBJECT_CLASS (parent_class)->restore_thyself)
|
|
||||||
GST_OBJECT_CLASS (parent_class)->restore_thyself (object, self);
|
|
||||||
}
|
|
||||||
#endif /* GST_DISABLE_LOADSAVE */
|
|
|
@ -1,88 +0,0 @@
|
||||||
/* GStreamer
|
|
||||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
|
||||||
* 2000 Wim Taymans <wtay@chello.be>
|
|
||||||
*
|
|
||||||
* gstthread.h: Header for GstThread object
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Library General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Library General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Library General Public
|
|
||||||
* License along with this library; if not, write to the
|
|
||||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
||||||
* Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef __GST_THREAD_H__
|
|
||||||
#define __GST_THREAD_H__
|
|
||||||
|
|
||||||
#include <glib.h>
|
|
||||||
|
|
||||||
#include <gst/gstbin.h>
|
|
||||||
|
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
|
||||||
|
|
||||||
extern GPrivate *gst_thread_current;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
GST_THREAD_STATE_SPINNING = GST_BIN_FLAG_LAST,
|
|
||||||
GST_THREAD_STATE_REAPING,
|
|
||||||
GST_THREAD_STATE_WAITING,
|
|
||||||
|
|
||||||
/* padding */
|
|
||||||
GST_THREAD_FLAG_LAST = GST_BIN_FLAG_LAST + 4
|
|
||||||
} GstThreadState;
|
|
||||||
|
|
||||||
#define GST_TYPE_THREAD (gst_thread_get_type())
|
|
||||||
#define GST_THREAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_THREAD,GstThread))
|
|
||||||
#define GST_IS_THREAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_THREAD))
|
|
||||||
#define GST_THREAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_THREAD,GstThreadClass))
|
|
||||||
#define GST_IS_THREAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_THREAD))
|
|
||||||
#define GST_THREAD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_THREAD, GstThreadClass))
|
|
||||||
|
|
||||||
typedef struct _GstThread GstThread;
|
|
||||||
typedef struct _GstThreadClass GstThreadClass;
|
|
||||||
|
|
||||||
struct _GstThread {
|
|
||||||
GstBin bin;
|
|
||||||
|
|
||||||
GThread *thread_id; /* id of the thread, if any */
|
|
||||||
GThreadPriority priority;
|
|
||||||
|
|
||||||
GMutex *lock; /* thread lock/condititon pairs */
|
|
||||||
GCond *cond; /* used to control the thread */
|
|
||||||
|
|
||||||
GMutex *iterate_lock; /* lock iteration in state change */
|
|
||||||
|
|
||||||
gpointer _gst_reserved[GST_PADDING-1];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _GstThreadClass {
|
|
||||||
GstBinClass parent_class;
|
|
||||||
|
|
||||||
/* signals */
|
|
||||||
void (*shutdown) (GstThread *thread);
|
|
||||||
|
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
|
||||||
};
|
|
||||||
|
|
||||||
GType gst_thread_get_type (void);
|
|
||||||
|
|
||||||
GstElement* gst_thread_new (const gchar *name);
|
|
||||||
|
|
||||||
void gst_thread_set_priority (GstThread *thread, GThreadPriority priority);
|
|
||||||
GstThread * gst_thread_get_current (void);
|
|
||||||
|
|
||||||
G_END_DECLS
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __GST_THREAD_H__ */
|
|
146
gst/gstutils.c
146
gst/gstutils.c
|
@ -610,10 +610,11 @@ GstPad *
|
||||||
gst_element_get_compatible_pad_filtered (GstElement * element, GstPad * pad,
|
gst_element_get_compatible_pad_filtered (GstElement * element, GstPad * pad,
|
||||||
const GstCaps * filtercaps)
|
const GstCaps * filtercaps)
|
||||||
{
|
{
|
||||||
const GList *pads;
|
GstIterator *pads;
|
||||||
GstPadTemplate *templ;
|
GstPadTemplate *templ;
|
||||||
GstCaps *templcaps;
|
GstCaps *templcaps;
|
||||||
GstPad *foundpad = NULL;
|
GstPad *foundpad = NULL;
|
||||||
|
gboolean done;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
||||||
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
|
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
|
||||||
|
@ -627,21 +628,56 @@ gst_element_get_compatible_pad_filtered (GstElement * element, GstPad * pad,
|
||||||
g_return_val_if_fail (pad != NULL, NULL);
|
g_return_val_if_fail (pad != NULL, NULL);
|
||||||
g_return_val_if_fail (GST_RPAD_PEER (pad) == NULL, NULL);
|
g_return_val_if_fail (GST_RPAD_PEER (pad) == NULL, NULL);
|
||||||
|
|
||||||
|
done = FALSE;
|
||||||
/* try to get an existing unlinked pad */
|
/* try to get an existing unlinked pad */
|
||||||
pads = gst_element_get_pad_list (element);
|
pads = gst_element_iterate_pads (element);
|
||||||
while (pads) {
|
while (!done) {
|
||||||
GstPad *current = GST_PAD (pads->data);
|
gpointer padptr;
|
||||||
|
|
||||||
|
switch (gst_iterator_next (pads, &padptr)) {
|
||||||
|
case GST_ITERATOR_OK:
|
||||||
|
{
|
||||||
|
GstPad *peer;
|
||||||
|
GstPad *current;
|
||||||
|
|
||||||
|
current = GST_PAD (padptr);
|
||||||
|
|
||||||
GST_CAT_LOG (GST_CAT_ELEMENT_PADS, "examing pad %s:%s",
|
GST_CAT_LOG (GST_CAT_ELEMENT_PADS, "examing pad %s:%s",
|
||||||
GST_DEBUG_PAD_NAME (current));
|
GST_DEBUG_PAD_NAME (current));
|
||||||
if (GST_PAD_PEER (current) == NULL &&
|
|
||||||
|
peer = gst_pad_get_peer (current);
|
||||||
|
|
||||||
|
if (peer == NULL &&
|
||||||
gst_pad_can_link_filtered (pad, current, filtercaps)) {
|
gst_pad_can_link_filtered (pad, current, filtercaps)) {
|
||||||
|
|
||||||
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
||||||
"found existing unlinked pad %s:%s", GST_DEBUG_PAD_NAME (current));
|
"found existing unlinked pad %s:%s",
|
||||||
|
GST_DEBUG_PAD_NAME (current));
|
||||||
|
|
||||||
|
gst_iterator_free (pads);
|
||||||
|
|
||||||
return current;
|
return current;
|
||||||
|
} else {
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "unreffing pads");
|
||||||
|
|
||||||
|
gst_object_unref (GST_OBJECT (current));
|
||||||
|
if (peer)
|
||||||
|
gst_object_unref (GST_OBJECT (peer));
|
||||||
}
|
}
|
||||||
pads = g_list_next (pads);
|
break;
|
||||||
}
|
}
|
||||||
|
case GST_ITERATOR_DONE:
|
||||||
|
done = TRUE;
|
||||||
|
break;
|
||||||
|
case GST_ITERATOR_RESYNC:
|
||||||
|
gst_iterator_resync (pads);
|
||||||
|
break;
|
||||||
|
case GST_ITERATOR_ERROR:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gst_iterator_free (pads);
|
||||||
|
|
||||||
/* try to create a new one */
|
/* try to create a new one */
|
||||||
/* requesting is a little crazy, we need a template. Let's create one */
|
/* requesting is a little crazy, we need a template. Let's create one */
|
||||||
|
@ -792,18 +828,24 @@ gst_element_link_pads_filtered (GstElement * src, const gchar * srcpadname,
|
||||||
if (!(GST_PAD_DIRECTION (srcpad) == GST_PAD_SRC)) {
|
if (!(GST_PAD_DIRECTION (srcpad) == GST_PAD_SRC)) {
|
||||||
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no src pad",
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no src pad",
|
||||||
GST_DEBUG_PAD_NAME (srcpad));
|
GST_DEBUG_PAD_NAME (srcpad));
|
||||||
|
gst_object_unref (GST_OBJECT (srcpad));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (GST_PAD_PEER (srcpad) != NULL) {
|
if (GST_PAD_PEER (srcpad) != NULL) {
|
||||||
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is already linked",
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is already linked",
|
||||||
GST_DEBUG_PAD_NAME (srcpad));
|
GST_DEBUG_PAD_NAME (srcpad));
|
||||||
|
gst_object_unref (GST_OBJECT (srcpad));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
srcpads = NULL;
|
srcpads = NULL;
|
||||||
} else {
|
} else {
|
||||||
srcpads = gst_element_get_pad_list (src);
|
GST_LOCK (src);
|
||||||
|
srcpads = GST_ELEMENT_PADS (src);
|
||||||
srcpad = srcpads ? (GstPad *) GST_PAD_REALIZE (srcpads->data) : NULL;
|
srcpad = srcpads ? (GstPad *) GST_PAD_REALIZE (srcpads->data) : NULL;
|
||||||
|
if (srcpad)
|
||||||
|
gst_object_ref (GST_OBJECT (srcpad));
|
||||||
|
GST_UNLOCK (src);
|
||||||
}
|
}
|
||||||
if (destpadname) {
|
if (destpadname) {
|
||||||
destpad = gst_element_get_pad (dest, destpadname);
|
destpad = gst_element_get_pad (dest, destpadname);
|
||||||
|
@ -815,23 +857,36 @@ gst_element_link_pads_filtered (GstElement * src, const gchar * srcpadname,
|
||||||
if (!(GST_PAD_DIRECTION (destpad) == GST_PAD_SINK)) {
|
if (!(GST_PAD_DIRECTION (destpad) == GST_PAD_SINK)) {
|
||||||
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no sink pad",
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no sink pad",
|
||||||
GST_DEBUG_PAD_NAME (destpad));
|
GST_DEBUG_PAD_NAME (destpad));
|
||||||
|
gst_object_unref (GST_OBJECT (destpad));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (GST_PAD_PEER (destpad) != NULL) {
|
if (GST_PAD_PEER (destpad) != NULL) {
|
||||||
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is already linked",
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is already linked",
|
||||||
GST_DEBUG_PAD_NAME (destpad));
|
GST_DEBUG_PAD_NAME (destpad));
|
||||||
|
gst_object_unref (GST_OBJECT (destpad));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
destpads = NULL;
|
destpads = NULL;
|
||||||
} else {
|
} else {
|
||||||
destpads = gst_element_get_pad_list (dest);
|
GST_LOCK (dest);
|
||||||
|
destpads = GST_ELEMENT_PADS (dest);
|
||||||
destpad = destpads ? (GstPad *) GST_PAD_REALIZE (destpads->data) : NULL;
|
destpad = destpads ? (GstPad *) GST_PAD_REALIZE (destpads->data) : NULL;
|
||||||
|
if (destpad)
|
||||||
|
gst_object_ref (GST_OBJECT (destpad));
|
||||||
|
GST_UNLOCK (dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (srcpadname && destpadname) {
|
if (srcpadname && destpadname) {
|
||||||
|
gboolean result;
|
||||||
|
|
||||||
/* two explicitly specified pads */
|
/* two explicitly specified pads */
|
||||||
return gst_pad_link_filtered (srcpad, destpad, filtercaps);
|
result = gst_pad_link_filtered (srcpad, destpad, filtercaps);
|
||||||
|
|
||||||
|
gst_object_unref (GST_OBJECT (srcpad));
|
||||||
|
gst_object_unref (GST_OBJECT (destpad));
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
if (srcpad) {
|
if (srcpad) {
|
||||||
/* loop through the allowed pads in the source, trying to find a
|
/* loop through the allowed pads in the source, trying to find a
|
||||||
|
@ -852,21 +907,32 @@ gst_element_link_pads_filtered (GstElement * src, const gchar * srcpadname,
|
||||||
filtercaps) == GST_PAD_LINK_OK) {
|
filtercaps) == GST_PAD_LINK_OK) {
|
||||||
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s",
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s",
|
||||||
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (temp));
|
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (temp));
|
||||||
|
if (destpad)
|
||||||
|
gst_object_unref (GST_OBJECT (destpad));
|
||||||
|
gst_object_unref (GST_OBJECT (srcpad));
|
||||||
|
gst_object_unref (GST_OBJECT (temp));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* find a better way for this mess */
|
/* find a better way for this mess */
|
||||||
if (srcpads) {
|
if (srcpads) {
|
||||||
srcpads = g_list_next (srcpads);
|
srcpads = g_list_next (srcpads);
|
||||||
if (srcpads)
|
if (srcpads) {
|
||||||
|
gst_object_unref (GST_OBJECT (srcpad));
|
||||||
srcpad = (GstPad *) GST_PAD_REALIZE (srcpads->data);
|
srcpad = (GstPad *) GST_PAD_REALIZE (srcpads->data);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} while (srcpads);
|
} while (srcpads);
|
||||||
}
|
}
|
||||||
if (srcpadname) {
|
if (srcpadname) {
|
||||||
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s:%s to %s",
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s:%s to %s",
|
||||||
GST_DEBUG_PAD_NAME (srcpad), GST_ELEMENT_NAME (dest));
|
GST_DEBUG_PAD_NAME (srcpad), GST_ELEMENT_NAME (dest));
|
||||||
|
gst_object_unref (GST_OBJECT (srcpad));
|
||||||
|
if (destpad)
|
||||||
|
gst_object_unref (GST_OBJECT (destpad));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
} else {
|
||||||
|
gst_object_unref (GST_OBJECT (srcpad));
|
||||||
}
|
}
|
||||||
if (destpad) {
|
if (destpad) {
|
||||||
/* loop through the existing pads in the destination */
|
/* loop through the existing pads in the destination */
|
||||||
|
@ -883,20 +949,33 @@ gst_element_link_pads_filtered (GstElement * src, const gchar * srcpadname,
|
||||||
filtercaps) == GST_PAD_LINK_OK) {
|
filtercaps) == GST_PAD_LINK_OK) {
|
||||||
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s",
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s",
|
||||||
GST_DEBUG_PAD_NAME (temp), GST_DEBUG_PAD_NAME (destpad));
|
GST_DEBUG_PAD_NAME (temp), GST_DEBUG_PAD_NAME (destpad));
|
||||||
|
gst_object_unref (GST_OBJECT (temp));
|
||||||
|
gst_object_unref (GST_OBJECT (destpad));
|
||||||
|
if (srcpad)
|
||||||
|
gst_object_unref (GST_OBJECT (srcpad));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (destpads) {
|
if (destpads) {
|
||||||
destpads = g_list_next (destpads);
|
destpads = g_list_next (destpads);
|
||||||
if (destpads)
|
if (destpads) {
|
||||||
|
gst_object_unref (GST_OBJECT (destpad));
|
||||||
destpad = (GstPad *) GST_PAD_REALIZE (destpads->data);
|
destpad = (GstPad *) GST_PAD_REALIZE (destpads->data);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} while (destpads);
|
} while (destpads);
|
||||||
}
|
}
|
||||||
if (destpadname) {
|
if (destpadname) {
|
||||||
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s to %s:%s",
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s to %s:%s",
|
||||||
GST_ELEMENT_NAME (src), GST_DEBUG_PAD_NAME (destpad));
|
GST_ELEMENT_NAME (src), GST_DEBUG_PAD_NAME (destpad));
|
||||||
|
gst_object_unref (GST_OBJECT (destpad));
|
||||||
|
if (srcpad)
|
||||||
|
gst_object_unref (GST_OBJECT (srcpad));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
} else {
|
||||||
|
gst_object_unref (GST_OBJECT (destpad));
|
||||||
|
if (srcpad)
|
||||||
|
gst_object_unref (GST_OBJECT (srcpad));
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
||||||
|
@ -923,6 +1002,8 @@ gst_element_link_pads_filtered (GstElement * src, const gchar * srcpadname,
|
||||||
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
||||||
"linked pad %s:%s to pad %s:%s",
|
"linked pad %s:%s to pad %s:%s",
|
||||||
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad));
|
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad));
|
||||||
|
gst_object_unref (GST_OBJECT (srcpad));
|
||||||
|
gst_object_unref (GST_OBJECT (destpad));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
/* it failed, so we release the request pads */
|
/* it failed, so we release the request pads */
|
||||||
|
@ -1111,8 +1192,8 @@ gst_element_unlink_many (GstElement * element_1, GstElement * element_2, ...)
|
||||||
void
|
void
|
||||||
gst_element_unlink (GstElement * src, GstElement * dest)
|
gst_element_unlink (GstElement * src, GstElement * dest)
|
||||||
{
|
{
|
||||||
const GList *srcpads;
|
GstIterator *pads;
|
||||||
GstPad *pad;
|
gboolean done = FALSE;
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_ELEMENT (src));
|
g_return_if_fail (GST_IS_ELEMENT (src));
|
||||||
g_return_if_fail (GST_IS_ELEMENT (dest));
|
g_return_if_fail (GST_IS_ELEMENT (dest));
|
||||||
|
@ -1120,23 +1201,46 @@ gst_element_unlink (GstElement * src, GstElement * dest)
|
||||||
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "unlinking \"%s\" and \"%s\"",
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "unlinking \"%s\" and \"%s\"",
|
||||||
GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
|
GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
|
||||||
|
|
||||||
srcpads = gst_element_get_pad_list (src);
|
pads = gst_element_iterate_pads (src);
|
||||||
|
while (!done) {
|
||||||
|
gpointer data;
|
||||||
|
|
||||||
while (srcpads) {
|
switch (gst_iterator_next (pads, &data)) {
|
||||||
pad = GST_PAD (srcpads->data);
|
case GST_ITERATOR_OK:
|
||||||
|
{
|
||||||
|
GstPad *pad = GST_PAD_CAST (data);
|
||||||
|
|
||||||
/* we only care about real src pads */
|
/* we only care about real src pads */
|
||||||
if (GST_IS_REAL_PAD (pad) && GST_PAD_IS_SRC (pad)) {
|
if (GST_IS_REAL_PAD (pad) && GST_PAD_IS_SRC (pad)) {
|
||||||
GstPad *peerpad = GST_PAD_PEER (pad);
|
GstPad *peerpad = gst_pad_get_peer (pad);
|
||||||
|
|
||||||
/* see if the pad is connected and is really a pad
|
/* see if the pad is connected and is really a pad
|
||||||
* of dest */
|
* of dest */
|
||||||
if (peerpad && (GST_OBJECT_PARENT (peerpad) == (GstObject *) dest)) {
|
if (peerpad) {
|
||||||
|
GstElement *peerelem = gst_pad_get_parent (peerpad);
|
||||||
|
|
||||||
|
if (peerelem == dest) {
|
||||||
gst_pad_unlink (pad, peerpad);
|
gst_pad_unlink (pad, peerpad);
|
||||||
}
|
}
|
||||||
}
|
if (peerelem)
|
||||||
|
gst_object_unref (GST_OBJECT (peerelem));
|
||||||
|
|
||||||
srcpads = g_list_next (srcpads);
|
gst_object_unref (GST_OBJECT (peerpad));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gst_object_unref (GST_OBJECT (pad));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GST_ITERATOR_RESYNC:
|
||||||
|
gst_iterator_resync (pads);
|
||||||
|
break;
|
||||||
|
case GST_ITERATOR_DONE:
|
||||||
|
done = TRUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -289,24 +289,50 @@ gst_parse_free_link (link_t *link)
|
||||||
if (link->caps) gst_caps_unref (link->caps);
|
if (link->caps) gst_caps_unref (link->caps);
|
||||||
gst_parse_link_free (link);
|
gst_parse_link_free (link);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_parse_element_lock (GstElement *element, gboolean lock)
|
gst_parse_element_lock (GstElement *element, gboolean lock)
|
||||||
{
|
{
|
||||||
GstPad *pad;
|
GstPad *pad;
|
||||||
GList *walk = (GList *) gst_element_get_pad_list (element);
|
GstIterator *pads;
|
||||||
gboolean unlocked_peer = FALSE;
|
gboolean unlocked_peer = FALSE;
|
||||||
|
gboolean done = FALSE;
|
||||||
|
GList *walk;
|
||||||
|
|
||||||
if (gst_element_is_locked_state (element) == lock)
|
if (gst_element_is_locked_state (element) == lock)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* check if we have an unlocked peer */
|
/* check if we have an unlocked peer */
|
||||||
for (; walk; walk = walk->next) {
|
pads = gst_element_iterate_pads (element);
|
||||||
pad = (GstPad *) GST_PAD_REALIZE (walk->data);
|
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) &&
|
if (GST_PAD_IS_SINK (pad) && GST_PAD_PEER (pad) &&
|
||||||
!gst_element_is_locked_state (GST_PAD_PARENT (GST_PAD_PEER (pad)))) {
|
!gst_element_is_locked_state (GST_PAD_PARENT (GST_PAD_PEER (pad)))) {
|
||||||
unlocked_peer = TRUE;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
gst_iterator_free (pads);
|
||||||
|
|
||||||
if (!(lock && unlocked_peer)) {
|
if (!(lock && unlocked_peer)) {
|
||||||
GST_CAT_DEBUG (GST_CAT_PIPELINE, "setting locked state on element");
|
GST_CAT_DEBUG (GST_CAT_PIPELINE, "setting locked state on element");
|
||||||
|
@ -325,7 +351,7 @@ gst_parse_element_lock (GstElement *element, gboolean lock)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if there are other pads to (un)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) {
|
for (; walk; walk = walk->next) {
|
||||||
pad = (GstPad *) GST_PAD_REALIZE (walk->data);
|
pad = (GstPad *) GST_PAD_REALIZE (walk->data);
|
||||||
if (GST_PAD_IS_SRC (pad) && GST_PAD_PEER (pad)) {
|
if (GST_PAD_IS_SRC (pad) && GST_PAD_PEER (pad)) {
|
||||||
|
|
|
@ -91,7 +91,7 @@ main (int argc, char *argv[])
|
||||||
padtemplate->name_template);
|
padtemplate->name_template);
|
||||||
}
|
}
|
||||||
|
|
||||||
pads = gst_element_get_pad_list (element);
|
pads = element->pads;
|
||||||
while (pads) {
|
while (pads) {
|
||||||
pad = (GstPad *) (pads->data);
|
pad = (GstPad *) (pads->data);
|
||||||
pads = g_list_next (pads);
|
pads = g_list_next (pads);
|
||||||
|
|
|
@ -603,7 +603,7 @@ print_pad_info (GstElement * element)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pads = gst_element_get_pad_list (element);
|
pads = element->pads;
|
||||||
while (pads) {
|
while (pads) {
|
||||||
pad = GST_PAD (pads->data);
|
pad = GST_PAD (pads->data);
|
||||||
pads = g_list_next (pads);
|
pads = g_list_next (pads);
|
||||||
|
|
|
@ -532,6 +532,7 @@ main (int argc, char *argv[])
|
||||||
|
|
||||||
end:
|
end:
|
||||||
|
|
||||||
|
fprintf (stderr, _("FREEING pipeline ...\n"));
|
||||||
gst_object_unref (GST_OBJECT (pipeline));
|
gst_object_unref (GST_OBJECT (pipeline));
|
||||||
|
|
||||||
if (trace)
|
if (trace)
|
||||||
|
|
|
@ -576,7 +576,7 @@ print_element_info (GstElementFactory * factory)
|
||||||
if (element->numpads) {
|
if (element->numpads) {
|
||||||
const GList *pads;
|
const GList *pads;
|
||||||
|
|
||||||
pads = gst_element_get_pad_list (element);
|
pads = element->pads;
|
||||||
while (pads) {
|
while (pads) {
|
||||||
pad = GST_PAD (pads->data);
|
pad = GST_PAD (pads->data);
|
||||||
pads = g_list_next (pads);
|
pads = g_list_next (pads);
|
||||||
|
|
Loading…
Reference in a new issue