docs: go over design docs and fix things
[platform/upstream/gstreamer.git] / docs / design / part-element-transform.txt
1 Transform elements
2 ------------------
3
4 Transform elements transform input buffers to output buffers based
5 on the sink and source caps. 
6
7 An important requirement for a transform is that the ouput caps are completely
8 defined by the input caps and vice versa. This means that a typical decoder
9 element can NOT be implemented with a transform element, this is because the
10 output caps like width and height of the decompessed video frame, for example,
11 are endcoded in the stream and thus not defined by the input caps.
12
13 Typical transform elements include:
14
15  - audio convertors (audioconvert, audioresample,...)
16  - video convertors (colorspace, videoscale, ...)
17  - filters (capfilter, volume, colorbalance, ...)
18
19 The implementation of the transform element has to take care of
20 the following things:
21
22  - efficient negotiation both up and downstream
23  - efficient buffer alloc and other buffer management
24
25 Some transform elements can operate in different modes:
26
27  - passthrough (no changes are done on the input buffers)
28  - in-place (changes made directly to the incomming buffers without requiring a
29    copy or new buffer allocation)
30  - metadata changes only 
31  
32 Depending on the mode of operation the buffer allocation strategy might change.
33
34 The transform element should at any point be able to renegotiate sink and src
35 caps as well as change the operation mode.
36
37 In addition, the transform element will typically take care of the following
38 things as well:
39
40  - flushing, seeking
41  - state changes
42  - timestamping, this is typically done by copying the input timestamps to the
43    output buffers but subclasses should be able to override this.
44  - QoS, avoiding calls to the subclass transform function
45  - handle scheduling issues such as push and pull based operation.
46
47 In the next sections, we will describe the behaviour of the transform element in
48 each of the above use cases. We focus mostly on the buffer allocation strategies
49 and caps negotiation.
50
51 Processing
52 ~~~~~~~~~~
53
54 A transform has 2 main processing functions:
55
56  - transform():
57
58    Transform the input buffer to the output buffer. The output buffer is
59    guaranteed to be writable and different from the input buffer.
60
61  - transform_ip():
62
63    Transform the input buffer in-place. The input buffer is writable and of
64    bigger or equal size than the output buffer. 
65
66 A transform can operate in the following modes:
67
68  - passthrough:
69
70    The element will not make changes to the buffers, buffers are pushed straight
71    through, caps on both sides need to be the same. The element can optionally
72    implement a transform_ip() function to take a look at the data, the buffer
73    does not have to be writable.
74
75  - in-place:
76
77    Changes can be made to the input buffer directly to obtain the output buffer.
78    The transform must implement a transform_ip() function.
79
80  - copy-transform
81
82    The transform is performed by copying and transforming the input buffer to a
83    new output buffer. The transform must implement a transform() function.
84
85 When no transform() function is provided, only in-place and passthrough
86 operation is allowed, this means that source and destination caps must be equal
87 or that the source buffer size is bigger or equal than the destination buffer.
88
89 When no transform_ip() function is provided, only passthrough and
90 copy-transforms are supported. Providing this function is an optimisation that
91 can avoid a buffer copy.
92
93 When no functions are provided, we can only process in passthrough mode.
94
95
96 Negotiation
97 ~~~~~~~~~~~
98
99 Typical (re)negotiation of the transform element in push mode always goes from
100 sink to src, this means triggers the following sequence:
101  
102   - the sinkpad receives a new caps event.
103   - the transform function figures out what it can convert these caps to.
104   - try to see if we can configure the caps unmodified on the peer. We need to
105     do this because we prefer to not do anything.
106   - the transform configures itself to transform from the new sink caps to the
107     target src caps
108   - the transform processes and sets the output caps on the src pad
109
110 We call this downstream negotiation (DN) and it goes roughly like this:
111
112                sinkpad              transform               srcpad
113      CAPS event   |                    |                      |
114      ------------>|  find_transform()  |                      |
115                   |------------------->|                      |
116                   |                    |       CAPS event     |
117                   |                    |--------------------->|
118                   | <configure caps> <-|                      |
119
120
121 These steps configure the element for a transformation from the input caps to
122 the output caps.
123
124 The transform has 3 function to perform the negotiation:
125
126    - transform_caps():
127      
128      Transform the caps on a certain pad to all the possible supported caps on
129      the other pad. The input caps are guaranteed to be a simple caps with just
130      one structure. The caps do not have to be fixed.
131       
132    - fixate_caps():
133
134      Given a caps on one pad, fixate the caps on the other pad. The target caps
135      are writable.
136
137    - set_caps():
138
139      Configure the transform for a transformation between src caps and dest
140      caps. Both caps are guaranteed to be fixed caps.
141
142 If no transform_caps() is defined, we can only perform the identity transform,
143 by default. 
144
145 If no set_caps() is defined, we don't care about caps. In that case we also
146 assume nothing is going to write to the buffer and we don't enforce a writable
147 buffer for the transform_ip function, when present.
148
149 One common function that we need for the transform element is to find the best
150 transform from one format (src) to another (dest). Some requirements of this
151 function are:
152
153    - has a fixed src caps
154    - finds a fixed dest caps that the transform element can transform to
155    - the dest caps are compatible and can be accepted by peer elements
156    - the transform function prefers to make src caps == dest caps
157    - the transform function can optionally fixate dest caps.
158
159 The find_transform() function goes like this:
160
161    - start from src aps, these caps are fixed.
162    - check if the caps are acceptable for us as src caps. This is usually
163      enforced by the padtemplate of the element.
164    - calculate all caps we can transform too with transform_caps()
165    - if the original caps are a subset of the transforms, try to see if the
166      the caps are acceptable for the peer. If this is possible, we can
167      perform passthrough and make src == dest.  This is performed by simply
168      calling gst_pad_peer_accept_caps().
169    - if the caps are not fixed, we need to fixate it, start by taking the peer
170      caps and intersect with them.
171    - for each of the transformed caps retrieved with transform_caps():
172       - try to fixate the caps with fixate_caps()
173       - if the caps are fixated, check if the peer accepts them with
174         _peer_accept_caps(), if the peer accepts, we have found a dest caps.
175    - if we run out of caps, we fail to find a transform.
176    - if we found a destination caps, configure the transform with set_caps().
177
178 After this negotiation process, the transform element is usually in a steady
179 state. We can identify these steady states:
180
181   - src and sink pads both have the same caps. Note that when the caps are equal
182     on both pads, the input and output buffers automatically have the same size.
183     The element can operate on the buffers in the following ways: (Same caps, SC)
184
185       - passthrough: buffers are inspected but no metadata or buffer data
186         is changed. The input buffers don't need to be writable. The input
187         buffer is simply pushed out again without modifications. (SCP)
188
189                sinkpad              transform               srcpad
190        chain()    |                    |                      |
191      ------------>|   handle_buffer()  |                      |
192                   |------------------->|      pad_push()      |
193                   |                    |--------------------->|
194                   |                    |                      |
195
196       - in-place: buffers are modified in-place, this means that the input
197         buffer is modified to produce a new output buffer. This requires the
198         input buffer to be writable. If the input buffer is not writable, a new
199         buffer has to be allocated from the bufferpool. (SCI)
200
201                sinkpad              transform               srcpad
202        chain()    |                    |                      |
203      ------------>|   handle_buffer()  |                      |
204                   |------------------->|                      |
205                   |                    |   [!writable]        |
206                   |                    |   alloc buffer       |
207                   |                  .-|                      |
208                   |  <transform_ip>  | |                      |
209                   |                  '>|                      |
210                   |                    |      pad_push()      |
211                   |                    |--------------------->|
212                   |                    |                      |
213
214       - copy transform: a new output buffer is allocate from the bufferpool
215         and data from the input buffer is transformed into the output buffer.
216         (SCC)
217
218                sinkpad              transform               srcpad
219        chain()    |                    |                      |
220      ------------>|   handle_buffer()  |                      |
221                   |------------------->|                      |
222                   |                    |     alloc buffer     |
223                   |                  .-|                      |
224                   |     <transform>  | |                      |
225                   |                  '>|                      |
226                   |                    |      pad_push()      |
227                   |                    |--------------------->|
228                   |                    |                      |
229
230   - src and sink pads have different caps. The element can operate on the
231     buffers in the following way: (Different Caps, DC)
232
233       - in-place: input buffers are modified in-place. This means that the input
234         buffer has a size that is larger or equal to the output size. The input
235         buffer will be resized to the size of the output buffer. If the input
236         buffer is not writable or the output size is bigger than the input size,
237         we need to pad-alloc a new buffer. (DCI)
238
239                sinkpad              transform               srcpad
240        chain()    |                    |                      |
241      ------------>|   handle_buffer()  |                      |
242                   |------------------->|                      |
243                   |                    | [!writable || !size] |
244                   |                    |     alloc buffer     |
245                   |                  .-|                      |
246                   |  <transform_ip>  | |                      |
247                   |                  '>|                      |
248                   |                    |      pad_push()      |
249                   |                    |--------------------->|
250                   |                    |                      |
251
252       - copy transform: a new output buffer is allocated and the data from the
253         input buffer is transformed into the output buffer. The flow is exactly
254         the same as the case with the same-caps negotiation. (DCC)
255  
256 We can immeditatly observe that the copy transform states will need to
257 allocate a new buffer from the bufferpool. When the transform element is
258 receiving a non-writable buffer in the in-place state, it will also
259 need to perform an allocation. There is no reason why the passthrough state would
260 perform an allocation.
261
262 This steady state changes when one of the following actions occur:
263
264   - the sink pad receives new caps, this triggers the above downstream
265     renegotation process, see above for the flow.
266   - the transform element wants to renegotiate (because of changed properties,
267     for example). This essentially clears the current steady state and
268     triggers the downstream and upstream renegotiation process. This situation
269     also happens when a RECONFIGURE event was received on the transform srcpad.
270
271
272 Allocation
273 ~~~~~~~~~~
274
275 After the transform element is configured with caps, a bufferpool needs to be
276 negotiated to perform the allocation of buffers. We habe 2 cases:
277
278   - The element is operating in passthrough we don't need to allocate a buffer
279     in the transform element.
280   - The element is not operating in passthrough and needs to allocation an
281     output buffer.
282
283 In case 1, we don't query and configure a pool. We let upstream decide if it
284 wants to use a bufferpool and then we will proxy the bufferpool from downstream
285 to upstream.
286
287 In case 2, we query and set a bufferpool on the srcpad that will be used for
288 doing the allocations.
289
290 In order to perform allocation, we need to be able to get the size of the
291 output buffer after the transform.  We need additional function to
292 retrieve the size. There are two functions:
293
294   - transform_size()
295     
296     Given a caps and a size on one pad, and a caps on the other pad, calculate
297     the size of the other buffer. This function is able to perform all size
298     transforms and is the prefered method of transforming a size.
299
300   - get_unit_size()
301
302     When the input size and output size are always a multiple of eachother
303     (audio conversion, ..) we can define a more simple get_unit_size() function.
304     The transform will use this function to get the same amount of units in the
305     source and destination buffers.
306
307  For performance reasons, the mapping between caps and size is kept in a cache.
308