mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-18 15:51:11 +00:00
153 lines
5.5 KiB
Text
153 lines
5.5 KiB
Text
|
Negotiation
|
||
|
-----------
|
||
|
|
||
|
Negotiation happens when elements want to push buffers and need to decide
|
||
|
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.
|
||
|
|
||
|
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. If no
|
||
|
previous buffer was received by a downstream element, it is free to
|
||
|
discard the 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 A | | Create buffer of type A.
|
||
|
| |
|
||
|
check type |<----------------|
|
||
|
and use A | |
|
||
|
| push |
|
||
|
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:
|
||
|
|
||
|
|
||
|
videotestsrc ! xvimagesink
|
||
|
|
||
|
1) Who decides what format to use?
|
||
|
- src pad always decides, by convention. sinkpad can suggest a format
|
||
|
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 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
|
||
|
it calls the pad alloc function with the type. The sinkpad has to
|
||
|
create a buffer of that type, src fills the buffer and sends it to sink.
|
||
|
- since the sink stated in 1) it could accept the type, it will be able to
|
||
|
create a buffer of the type and handle it.
|
||
|
- sink checks media type of buffer and configures itself for this type.
|
||
|
|
||
|
3) How can sink request another format?
|
||
|
- sink asks if new format is possible for the source.
|
||
|
- sink returns buffer with new type in allocfunction.
|
||
|
- src receives buffer with new type, reconfigures and pushes.
|
||
|
- sink can always select something it can create and handle since it takes
|
||
|
the initiative. src should be able to handle the new type since it said
|
||
|
it could accept it.
|
||
|
|
||
|
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.
|
||
|
|
||
|
|
||
|
|