mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-13 01:35:30 +00:00
docs/design/: Some docs updates.
Original commit message from CVS: * docs/design/part-TODO.txt: * docs/design/part-negotiation.txt: * docs/design/part-states.txt: Some docs updates.
This commit is contained in:
parent
b1d9edff2f
commit
883680f12b
3 changed files with 120 additions and 14 deletions
12
docs/design/part-TODO.txt
Normal file
12
docs/design/part-TODO.txt
Normal file
|
@ -0,0 +1,12 @@
|
|||
|
||||
- changing an object's name after construction is not allowed. Checks are performed
|
||||
when adding objects to parents that no duplicate names are used, changing the name
|
||||
to a duplicate name after adding it is therefore allowed and voids internal
|
||||
consistency.
|
||||
|
||||
- check for race in _task_pause()/_stop() since the TASK_LOCK is not held by the
|
||||
calling thread and the STREAM_LOCK not by the task code.
|
||||
|
||||
- only emit EOS in PLAYING.
|
||||
|
||||
- implement state change order on get<->loop-get<->loop elements.
|
|
@ -2,30 +2,116 @@ Negotiation
|
|||
-----------
|
||||
|
||||
Negotiation happens when elements want to push buffers and need to decide
|
||||
on the format.
|
||||
on the format. This is called downstream negotiation because the upstream
|
||||
element decides the format for the downstream element. This is the most
|
||||
common case.
|
||||
|
||||
For any two linked pads there are different ways to agree on the format but
|
||||
in general the source pad will propose a format and the sink format accepts
|
||||
or rejects.
|
||||
Negotiation can also happen when a downstream element wants to receive
|
||||
another data format from an upstream element. This is called upstream
|
||||
negotiation.
|
||||
|
||||
The basics of negotiation are as follows:
|
||||
|
||||
- GstCaps (see part-caps.txt) are attached and refcounted before they
|
||||
are attached to a buffer to describe the contents of the buffer.
|
||||
It is possible to add a NULL caps to a buffer, this means that the
|
||||
buffer type did not change relative to the previous buffer.
|
||||
|
||||
- Before receiving a buffer, an element must check if the datatype of
|
||||
the buffer has changed. The element should reconfigure itself to the
|
||||
new format before processing the buffer data. If the data type on
|
||||
the buffer is not acceptable, the element should refuse the buffer.
|
||||
|
||||
- When requesting a buffer from a bufferpool, the prefered type should
|
||||
be passed to the buffer allocation function. After receiving a buffer
|
||||
from a bufferpool, the datatype should be checked again.
|
||||
|
||||
- A bufferpool allocation function should try to allocate a buffer of the
|
||||
prefered type. If there is a good reason to choose another type, the
|
||||
alloc function should see if that other type is accepted by the other
|
||||
element, then allocate a buffer of that type and attach the type to the
|
||||
buffer before returning it.
|
||||
|
||||
|
||||
The general flow for a source pad starting the negotiation.
|
||||
|
||||
src sink
|
||||
| |
|
||||
| accepts? |
|
||||
|---------------->|
|
||||
type A |---------------->|
|
||||
| yes |
|
||||
|<----------------|
|
||||
| |
|
||||
get buffer | alloc_buf |
|
||||
from pool |---------------->|
|
||||
with type | | Create buffer of type.
|
||||
with type A | | Create buffer of type A.
|
||||
| |
|
||||
check type |<----------------|
|
||||
and use | |
|
||||
and use A | |
|
||||
| push |
|
||||
push buffer |---------------->| Receive type, reconfigure to
|
||||
with new type| | process type.
|
||||
push buffer |---------------->| Receive type A, reconfigure to
|
||||
with new type| | process type A.
|
||||
| |
|
||||
|
||||
One possible implementation in pseudo code:
|
||||
|
||||
[element wants to create a buffer]
|
||||
if not format
|
||||
# see what the peer can do
|
||||
peercaps = gst_pad_peer_get_caps (srcpad)
|
||||
# see what we can do
|
||||
ourcaps = gst_pad_get_caps (srcpad)
|
||||
|
||||
# get common formats
|
||||
candidates = gst_caps_intersect (peercaps, ourcaps)
|
||||
|
||||
foreach candidate in candidates
|
||||
# make sure the caps is fixed
|
||||
fixedcaps = gst_pad_fixate_caps (srcpad, candidate)
|
||||
|
||||
# see if the peer accepts it
|
||||
if gst_pad_peer_accept_caps (srcpad, fixedcaps)
|
||||
# store the caps as the negotiated caps, this will
|
||||
# call the setcaps function on the pad
|
||||
gst_pad_set_caps (srcpad, fixedcaps)
|
||||
break
|
||||
endif
|
||||
done
|
||||
endif
|
||||
|
||||
# if the type is different, this will call the setcaps function of
|
||||
# the pad.
|
||||
buffer = gst_pad_alloc_buffer (srcpad, 0, size, GST_PAD_CAPS (fixedcaps));
|
||||
if buffer
|
||||
[fill buffer and push]
|
||||
elseif
|
||||
[no buffer, either no peer or no acceptable format found]
|
||||
endif
|
||||
|
||||
|
||||
The general flow for a sink pad starting a renegotiation.
|
||||
|
||||
src sink
|
||||
| |
|
||||
| accepts? |
|
||||
|<----------------| type B
|
||||
| yes |
|
||||
|---------------->|
|
||||
| |
|
||||
get buffer | alloc_buf |
|
||||
from pool |---------------->|
|
||||
with type | | Create buffer of new type B.
|
||||
| |
|
||||
check type |<----------------|
|
||||
and | |
|
||||
reconfigure | |
|
||||
| push |
|
||||
push buffer |---------------->| Receive type B, reconfigure to
|
||||
with new type| | process type B.
|
||||
| |
|
||||
|
||||
|
||||
|
||||
Use case:
|
||||
|
||||
|
||||
|
@ -36,7 +122,7 @@ videotestsrc ! xvimagesink
|
|||
by putting it high in the getcaps function GstCaps.
|
||||
- since the src decides, it can always choose something that it can do,
|
||||
so this step can only fail if the sinkpad stated it could accept
|
||||
something while it later on couldn't.
|
||||
something while later on it couldn't.
|
||||
|
||||
2) When does negotiation happen?
|
||||
- before srcpad does a push, it figures out a type as stated in 1), then
|
||||
|
@ -58,6 +144,7 @@ videotestsrc ! queue ! xvimagesink
|
|||
|
||||
- queue implements an allocfunction, proxying all calls to its srcpad peer.
|
||||
- queue proxies all accept and getcaps to the other peer pad.
|
||||
- queue contains buffers with different types.
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -19,6 +19,9 @@ State definitions
|
|||
- PLAYING: The same as PAUSED except for sinks, who are now accepting
|
||||
and rendering data.
|
||||
|
||||
We call the sequence NULL->PLAYING an upwards state change and PLAYING->NULL
|
||||
a downwards state change.
|
||||
|
||||
|
||||
State variables
|
||||
---------------
|
||||
|
@ -105,11 +108,15 @@ States in GstBin
|
|||
----------------
|
||||
|
||||
A GstBin manages the state of its children. It does this by propagating the state
|
||||
changes performed on it to all of its children.
|
||||
changes performed on it to all of its children. The _set_state() function on a
|
||||
bin will call the _set_state() function on all of its children.
|
||||
|
||||
The _set_state() function on a bin will call the _set_state() function on all of
|
||||
its children. The children are iterated from the sink elements to the source
|
||||
elements.
|
||||
The children are iterated from the sink elements to the source elements. This makes
|
||||
sure that when changing the state of an element, the downstream elements are in
|
||||
the correct state to process the eventual buffers. In the case of a downwards
|
||||
state change, the sink elements will shut down first which makes the upstream
|
||||
elements shut down as well since the _push() function returns a GST_FLOW_WRONG_STATE
|
||||
error.
|
||||
|
||||
If all the children return SUCCESS, the function returns SUCCESS as well.
|
||||
|
||||
|
|
Loading…
Reference in a new issue