docs: update bufferpool design doc

Move the bufferpool design doc from draft to part and merge it with
the allocation draft.
This commit is contained in:
Wim Taymans 2011-06-03 12:43:32 +02:00
parent 89121c18e5
commit f7acae0af5
2 changed files with 102 additions and 216 deletions

View file

@ -1,51 +0,0 @@
Allocation
----------
This document outlines the requirements for determining how memory and buffers
will be allocated between to pads.
Overview
~~~~~~~~
After a particular media format has been negotiated between two pads, they must
agree on how to allocate buffers.
The srcpad will always take the initiative to negotiate the allocation
properties. It starts with creating a GST_QUERY_ALLOCATION with the negotiated
caps.
The srcpad can set the need-pool flag to TRUE in the query to optionally make the
peer pad allocate a bufferpool.
It will then inspect the returned results and configure the returned pool or
create a new pool when needed.
Buffers are then allocated by the srcpad from the negotiated pool.
Allocation query
~~~~~~~~~~~~~~~~
(in) "caps", GST_TYPE_CAPS
- the caps that was negotiated
(in) "need-pool", G_TYPE_BOOLEAN
- if a GstBufferPool is requested
(out) "prefix", G_TYPE_UINT
- the prefix of the buffer memory
(out) "align", G_TYPE_UINT
- the aligment of the memory in the buffers, the alignment will be applied
to the prefix.
(out) "size", G_TYPE_UINT
- the total size of the buffer memory
(out) "pool", GST_TYPE_BUFFER_POOL
- a buffer pool when need-pool was TRUE and the peer can provide a pool
(out) "metadata", G_TYPE_VALUE_ARRAY of G_TYPE_STRING
- an array of metadata API strings that can be accepted.

View file

@ -1,69 +1,37 @@
Bufferpool Bufferpool
---------- ----------
This document details a possible design for how buffers can be allocated This document details the design of how buffers are be allocated and
and managed in pools. managed in pools.
Bufferpools should increase performance by reducing allocation overhead and Bufferpools increases performance by reducing allocation overhead and
improving possibilities to implement zero-copy memory transfer. improving possibilities to implement zero-copy memory transfer.
Together with the ALLOCATION query, elements can negotiate allocation properties
Current Situation and bufferpools between themselves. This also allows elements to negotiate
----------------- buffer metadata between themselves.
- elements can choose to implement a pool of buffers. These pools
can contain buffers for both source and sink pad buffers.
- elements can provide buffers to upstream elements when the upstream element
requests a buffer with gst_pad_alloc_buffer().
- The buffer pool can preallocate a certain amount of buffers to avoid
runtime allocation. pad_alloc_buffer() is allowed to block the upstream
element until buffers are recycled in the pool.
- the pad_alloc_buffer function call can be passed downstream to the sink
that actually will perform the allocation. A fallback option exists to use
a default memory bufferpool whe there is no alloc_buffer function installed
on a pad.
- Upstream renegotiation is performed by making the pad_alloc_buffer function
return a buffer with new caps.
Problems
--------
- There is currently no helper base class to implement efficient buffer pools
meaning that each element has to implement its own version.
- There is no negotiation between elements about their buffer requirements.
Upstream elements that decide to use pad_alloc_buffer() can find that the
buffer they received is not appropriate at all. The most common problem
is that the buffers don't have the right alignment or insufficient padding.
- There is no negotiation of minimum and maximum amounts of preallocated
buffers. In order to not avoid deadlocks, this means that buffer pool
implementations should be able to allocate unlimited amounts of buffers and
are never allowed to block in pad_alloc_buffer()
Requirements Requirements
------------ ------------
- maintain and reuse a list of buffers in a reusable base GstBufferPool - Provide a GstBufferPool base class to help the efficient implementation of a
object list of reusable GstBuffer objects.
- negotiate allocation configuration between source and sink pad. - Let upstream elements initiate the negotiation of a bufferpool and it
- have minimum and maximum amount of buffers with the option of configuration. Allow downstream elements provide bufferpool properties and/or
preallocating buffers. a bufferpool. This includes the following properties:
- alignment and padding support
- arbitrary extra options
- integrate with dynamic caps renegotiation * have minimum and maximum amount of buffers with the option of
preallocating buffers.
* alignment and padding support
* buffer metadata
* arbitrary extra options
- dynamically change bufferpool configuration based on pipeline changes. - Integrate with dynamic caps renegotiation.
- allow the application to control buffer allocation - Notify upstream element of new bufferpool availability. This is important
when a new element, that can provide a bufferpool, is dynamically linked
downstream.
GstBufferPool GstBufferPool
@ -85,79 +53,53 @@ GstBufferPool
different allocation strategies such as using shared memory or hardware different allocation strategies such as using shared memory or hardware
mapped memory. mapped memory.
The bufferpool object is also used to perform the negotiation of configuration
between elements. Negotiation
-----------
After a particular media format has been negotiated between two pads (using the
CAPS event), they must agree on how to allocate buffers.
The srcpad will always take the initiative to negotiate the allocation
properties. It starts with creating a GST_QUERY_ALLOCATION with the negotiated
caps.
The srcpad can set the need-pool flag to TRUE in the query to optionally make the
peer pad allocate a bufferpool.
It will then inspect the returned results and configure the returned pool or
create a new pool with the returned properties when needed.
Buffers are then allocated by the srcpad from the negotiated pool and pushed to
the peer pad as usual.
GstPad Allocation query
------ ----------------
A GstPad can query a new bufferpool from a peer element withe the BUFFERPOOL The allocation query has the following fields:
query.
The returned bufferpool object can then be configured with the desired (in) "caps", GST_TYPE_CAPS
parameters of the buffers it should provide. - the caps that was negotiated
When the bufferpool is configured, it must be pushed downstream with the
BUFFERPOOL event. This is to inform a pad and its peer pad that a bufferpool
should be used for allocation (on source pads) and that bufferpool is used
by the upstream element (on sinkpads).
negotiating pool and config (in) "need-pool", G_TYPE_BOOLEAN
--------------------------- - if a GstBufferPool is requested
Since upstream needs to allocate buffers from a buffer pool, it should first (out) "prefix", G_TYPE_UINT
negotiate a buffer pool with the downstream element. We propose a simple - the prefix of the buffer memory
scheme where a sink can propose a bufferpool and some configuration and where
the source can choose to use this allocator or use its own.
The algorithm for doing this is roughly like this: (out) "align", G_TYPE_UINT
- the aligment of the memory in the buffers, the alignment will be applied
to the prefix.
(out) "size", G_TYPE_UINT
- the total size of the buffer memory
/* srcpad knows media type and size of buffers and is ready to (out) "pool", GST_TYPE_BUFFER_POOL
* prepare an output buffer but has no pool yet */ - a buffer pool when need-pool was TRUE and the peer can provide a pool
/* first get the pool from the downstream peer */ (out) "metadata", G_TYPE_VALUE_ARRAY of G_TYPE_STRING
res = gst_pad_query_bufferpool (srcpad, &pool); - an array of metadata API strings that can be accepted.
if (pool != NULL) {
GstBufferPoolConfig config;
/* clear the pool so that we can reconfigure it */
gst_buffer_pool_set_active (pool, FALSE);
do {
/* get the config */
gst_buffer_pool_get_config (pool, &config);
/* check and modify the config to match our requirements */
if (!tweak_config (&config)) {
/* we can't tweak the config any more, exit and fail */
gst_object_unref (pool);
pool = NULL;
break;
}
}
/* update the config */
while (!gst_buffer_pool_set_config (pool, &config));
/* we managed to update the config, all is fine now */
/* set the pool to active to make it allocate things */
gst_buffer_pool_set_active (pool, TRUE);
}
if (pool == NULL) {
/* still no pool, we create one ourself with our ideal config */
pool = gst_buffer_pool_new (...);
}
/* now set the pool on this pad and the peer pad */
gst_pad_push_event (pad, gst_event_new_bufferpool (pool));
Negotiation is the same for both push and pull mode. In the case of pull
mode scheduling, the srcpad will perform the negotiation of the pool
when it receives the first pull request.
Allocating from pool Allocating from pool
@ -167,19 +109,31 @@ Allocating from pool
res = gst_buffer_pool_acquire_buffer (pool, &buffer, &params); res = gst_buffer_pool_acquire_buffer (pool, &buffer, &params);
convenience functions to automatically get the pool from a pad can be made: A GstBuffer that is allocated from the pool will always be writable (have a
refcount of 1) and it will also have its pool member point to the GstBufferPool
res = gst_pad_acquire_buffer (pad, &buffer, &params); that created the buffer.
Buffers are refcounted in te usual way. When the refcount of the buffer Buffers are refcounted in the usual way. When the refcount of the buffer
reaches 0, the buffer is automatically returned to the pool. This is achieved reaches 0, the buffer is automatically returned to the pool.
by setting and reffing the pool as a new buffer member.
Since all the buffers allocated from the pool keep a reference to the pool, Since all the buffers allocated from the pool keep a reference to the pool,
when nothing else is holding a refcount to the pool, it will be finalized when nothing else is holding a refcount to the pool, it will be finalized
when all the buffers from the pool are unreffed. By setting the pool to when all the buffers from the pool are unreffed. By setting the pool to
the inactive state we can drain all buffers from the pool. the inactive state we can drain all buffers from the pool.
When the pool is in the inactive state, gst_buffer_pool_acquire_buffer() will
return GST_FLOW_WRONG_STATE immediately.
Extra parameters can be given to the gst_buffer_pool_acquire_buffer() method to
influence the allocation decision. GST_BUFFER_POOL_FLAG_KEY_UNIT and
GST_BUFFER_POOL_FLAG_DISCONT serve as hints.
When the bufferpool is configured with a maximum number of buffers, allocation
will block when all buffers are outstanding until a buffer is returned to the
pool. This behaviour can be changed by specifying the
GST_BUFFER_POOL_FLAG_DONTWAIT flag in the parameters. With this flag set,
allocation will return GST_FLOW_UNEXPECTED when the pool is empty.
Renegotiation Renegotiation
------------- -------------
@ -203,7 +157,8 @@ of a caps change), alignment or number of buffers.
the drain to finish before reconfiguring the pool. the drain to finish before reconfiguring the pool.
The element that wants to renegotiate a new bufferpool uses exactly the same The element that wants to renegotiate a new bufferpool uses exactly the same
algorithm as when it first started. algorithm as when it first started. It will negotiate caps first then use the
ALLOCATION query to get and configure the new pool.
* upstream * upstream
@ -220,11 +175,6 @@ of a caps change), alignment or number of buffers.
The next buffer allocation will then require the renegotiation or The next buffer allocation will then require the renegotiation or
reconfiguration of a pool. reconfiguration of a pool.
If downstream has specified a RENEGOTIATE flag, it must be prepared to
received NOT_NEGOTIATED results when allocating buffers, which instructs
it to start caps and bufferpool renegotiation. When using this flag,
upstream can more quickly react to downstream format or size changes.
Shutting down Shutting down
------------- -------------
@ -240,7 +190,6 @@ Shutting down
automatically be freed by the pool and new allocations will fail. automatically be freed by the pool and new allocations will fail.
Use cases Use cases
--------- ---------
@ -250,36 +199,32 @@ Use cases
a bufferpool with the downstream peer pad. a bufferpool with the downstream peer pad.
First it will negotiate a suitable format with downstream according to the First it will negotiate a suitable format with downstream according to the
normal rules. normal rules. It will send a CAPS event downstream with the negotiated
configuration.
Then it does gst_pad_query_bufferpool() which triggers the BUFFERPOOL query. Then it does an ALLOCATION query. It will use the returned bufferpool or
This bufferpool is currently in the inactive state and thus has no buffers configures its own bufferpool with the returned parameters. The bufferpool is
allocated. initially in the inactive state.
videotestsrc gets the configuration of the bufferpool object. This The ALLOCATION query lists the desired configuration of the downstream
configuration lists the desired configuration of the xvimagesink, which can xvimagesink, which can have specific alignment and/or min/max amount of
have specific alignment and/or min/max amount of buffers. buffers.
videotestsrc updates the configuration of the bufferpool, it will likely videotestsrc updates the configuration of the bufferpool, it will likely
set the min buffers to 1 and the size of the desired buffers. It then set the min buffers to 1 and the size of the desired buffers. It then
updates the bufferpool configuration with the new properties. updates the bufferpool configuration with the new properties.
When the configuration is successfully updated, videotestsrc pushes the When the configuration is successfully updated, videotestsrc sets the
bufferpool downstream with the BUFFERPOOL event. bufferpool to the active state. This preallocates the buffers in the pool
(if needed). This operation can fail when there is not enough memory
It then sets the bufferpool to the active state. This preallocates available. Since the bufferpool is provided by xvimagesink, it will allocate
the buffers in the pool (if needed). This operation can fail when there buffers backed by an XvImage and pointing to shared memory with the X server.
is not enough memory available. Since the bufferpool is provided by
xvimagesink, it will allocate buffers backed by an XvImage and pointing
to shared memory with the X server.
If the bufferpool is successfully activated, videotestsrc can acquire a If the bufferpool is successfully activated, videotestsrc can acquire a
buffer from the pool, set the caps on it, fill in the data and push it buffer from the pool, fill in the data and push it out to xvimagesink.
out to xvimagesink.
xvimagesink can know that the buffer originated from its pool by following xvimagesink can know that the buffer originated from its pool by following
the pool member. It might need to get the parent buffer first in case of the pool member.
subbuffers.
when shutting down, videotestsrc will set the pool to the inactive state, when shutting down, videotestsrc will set the pool to the inactive state,
this will cause further allocations to fail and currently allocated buffers this will cause further allocations to fail and currently allocated buffers
@ -292,7 +237,7 @@ Use cases
3 video buffers. 3 video buffers.
Again videotestsrc will have to negotiate a bufferpool with the peer Again videotestsrc will have to negotiate a bufferpool with the peer
element. For this it will perform gst_pad_query_bufferpool() which element. For this it will perform the ALLOCATION query which
queue will proxy to its downstream peer element. queue will proxy to its downstream peer element.
The bufferpool returned from myvideosink will have a max_buffers set to 3. The bufferpool returned from myvideosink will have a max_buffers set to 3.
@ -305,14 +250,10 @@ Use cases
rules. When videotestsrc sets the pool to active, the 3 video rules. When videotestsrc sets the pool to active, the 3 video
buffers will be preallocated in the pool. buffers will be preallocated in the pool.
The pool will then be configured to downstream elements with the BUFFERPOOL
event. The queue will proxy the BUFFERPOOL event to its srcpad, which
finally configures the pool all the way to the sink.
videotestsrc acquires a buffer from the configured pool on its srcpad and videotestsrc acquires a buffer from the configured pool on its srcpad and
pushes this into the queue. When the videotestsrc has acquired and pushed pushes this into the queue. When the videotestsrc has acquired and pushed
3 frames, the next call to gst_buffer_pool_acquire_buffer() will block 3 frames, the next call to gst_buffer_pool_acquire_buffer() will block
(assuming the GST_BUFFER_POOL_FLAG_WAIT is specified). (assuming the GST_BUFFER_POOL_FLAG_DONTWAIT is not specified).
When the queue has pushed out a buffer and the sink has rendered it, the When the queue has pushed out a buffer and the sink has rendered it, the
refcount of the buffer reaches 0 and the buffer is recycled in the pool. refcount of the buffer reaches 0 and the buffer is recycled in the pool.
@ -337,14 +278,13 @@ Use cases
When it negotiates the size with the downstream element fakesink, it will When it negotiates the size with the downstream element fakesink, it will
receive a NULL bufferpool because fakesink does not provide a bufferpool. receive a NULL bufferpool because fakesink does not provide a bufferpool.
It will then select it own custom bufferpool to start the datatransfer. It will then select its own custom bufferpool to start the datatransfer.
At some point we block the queue srcpad, unlink the queue from the At some point we block the queue srcpad, unlink the queue from the
fakesink, link a new sink, set the new sink to the PLAYING state and send fakesink, link a new sink and set the new sink to the PLAYING state.
the right newsegment event to the sink. Linking the new sink would Linking the new sink would automatically send a RECONFIGURE event upstream
automatically send a RENEGOTIATE event upstream and, through queue, inform and, through queue, inform myvideodecoder that it should renegotiate its
myvideodecoder that it should renegotiate its bufferpool because downstream bufferpool because downstream has been reconfigured.
has been reconfigured.
Before pushing the next buffer, myvideodecoder would renegotiate a new Before pushing the next buffer, myvideodecoder would renegotiate a new
bufferpool. To do this, it performs the usual bufferpool negotiation bufferpool. To do this, it performs the usual bufferpool negotiation
@ -366,9 +306,8 @@ Use cases
When myvideodecoder needs to get the bigger buffer, it starts the When myvideodecoder needs to get the bigger buffer, it starts the
negotiation of a new bufferpool. It queries a bufferpool from downstream, negotiation of a new bufferpool. It queries a bufferpool from downstream,
reconfigures it with the new configuration (which includes the bigger buffer reconfigures it with the new configuration (which includes the bigger buffer
size), it sets the bufferpool to active and pushes the bufferpool downstream. size) and it then sets the bufferpool to active. The old pool is inactivated
This automatically inactivates the old pool and unrefs it, which causes the and unreffed, which causes the old format to drain.
old format to drain.
It then uses the new bufferpool for allocating new buffers of the new It then uses the new bufferpool for allocating new buffers of the new
dimension. dimension.
@ -383,10 +322,8 @@ Use cases
myvideosink is providing a bufferpool for upstream elements and wants to myvideosink is providing a bufferpool for upstream elements and wants to
change the resolution. change the resolution.
myvideosink sends a RENEGOTIATE event upstream to notify upstream that a myvideosink sends a RECONFIGURE event upstream to notify upstream that a
new format is desirable. upstream elements try to negotiate a new format new format is desirable. upstream elements try to negotiate a new format
and bufferpool before pushing out a new buffer. The old bufferpools are and bufferpool before pushing out a new buffer. The old bufferpools are
drained in the regular way. drained in the regular way.