summaryrefslogtreecommitdiff
path: root/docs/design/draft-buffer2.txt
blob: d55fce0f4054b6120f0ce1de297f8aee4af64bbe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
GstBuffer^2
-----------

This draft document describes a possible design for arbitrary per-buffer
metadata.

The proposed changes in this document are not ABI/API compatible with the 0.10
version of GStreamer and should thus only be considered for upcomming unstable
versions.

Buffer metadata typically includes properties that give more information about
the buffer contents. These properties are usually not negotiated and are thus
not inside the caps.

Some examples of metadata:

 - timestamp, duration
 - offset, offset_end
 - interlacing information
 - video alignment, cropping, panning information
 - extra container information such as granulepos, ...
 - extra global buffer properties


Requirements
------------

 - It must be fast
    * allocation, free, low fragmentation
    * access to the metadata fields, preferably not much slower than directly
      accessing a C structure field
 - It must be extensible. Elements should be able to add new arbitrary metadata
   without requiring much effort. Also new metadata fields should not break API
   or ABI.
 - It plays nice with subbuffers. When a subbuffer is created, the various
   buffer metadata should be copied/updated correctly.
 - We should be able to pass metadata in pad_alloc() and get_range() functions
   to specify extra allocation parameters.
 - We should be able to attach statically allocated metadata to a buffer. This
   is for metadata that does not change much.


GstMiniObject
-------------

We make GstMiniObject a simple refcounted C structure and also a GLib boxed
type. The following fields will be in the structure:

struct _GstMiniObject {
  GType type;

  /*< public >*/ /* with COW */
  /* refcounting */
  gint       refcount;
  guint      flags;

  GstMiniObjectCopyFunction copy;
  GstMiniObjectFreeFunction free;
}

We will use the regular GSlice allocator or custom object pooling for allocating
instances of the mini object.

We use the well known refcounting mechanisms to manage the lifetime of the
objects.


GstEvent, GstCaps, GstQuery, GstMessage
---------------------------------------

Have the new GstMiniObject be the first field in these objects. They will probably
also replace the copy and free functions with their own implementations.

Allocation of the objects will use the regular gst_*_new() functions that will
allocate and initialize a parent GstMiniObject of the required size and setting up
the custom functions.


GstBuffer
---------

A GstMiniObject will be the parent instance of the GstBuffer object, which is a
regular C structure.

struct _GstBuffer {
  GstMiniObject          mini_object;

  gsize                  free_size;

  GstCaps               *caps;
  GstBuffer             *parent;

  gpointer _gst_padding[10];
};

The Buffer object will contain a pointer to the parent buffer to allow for subbuffers
as a first class feature of a GstBuffer.

Allocation of the GstBuffer structure will result in the allocation of a memory region
of a customizable size (512 bytes). Only the first sizeof (GstBuffer) bytes of this
region will initially be used. The remaining bytes will be part of the free metadata
region of the buffer. The size of the free region is kept in the free_size field.

Buffers point to a GstCaps structure that contains the caps of the buffer data.


GstBufferMeta
-------------

A GstBufferMeta is a structure as follows:

  struct _GstBufferMeta {
    GstBufferMetaInfo *info;  /* tag and info for the meta item */
    GstBufferMeta     *next;  /* pointer to the next item */
  }

The purpose of the this structure is to serve as a common header for all metadata
information that we can attach to a buffer. Specific metadata, such as timing metadata,
will have this structure as the first field. For example:

  struct _GstBufferMetaTiming {
    GstBufferMeta  meta;        /* common meta header */
 
    GstClockTime   dts;         /* decoding timestamp */
    GstClockTime   pts;         /* presentation timestamp */
    GstClockTime   duration;    /* duration of the data */
    GstClockTime   clock_rate;  /* clock rate for the above values */
  };

Or another example for the buffer memory region

  struct _GstBufferMetaMemory {
    GstBufferMeta      meta;
   
    /* pointer to data and its size */
    guint8            *data;
    guint              size;
    guint8            *malloc_data;
    GFreeFunc          data_free;
    gpointer           data_user;
  };

GstBufferMetaInfo will point to more information about the metadata and looks like this:

  struct _GstBufferMetaInfo {
    GQuark                     tag;       /* tag name */
    gsize                      size;      /* size of the structure */

    GstMetaInitFunction        init_func;
    GstMetaFreeFunction        free_func;
    GstMetaSubFunction         sub_func;
    GstMetaSerializeFunction   serialize_func
    GstMetaDeserializeFunction deserialize_func
  }

Tag will contain a GQuark of the metadata name. We will be able to refer to specific
metadata by name or by its (cached) GQuark.  A repository of registered MetaInfo
will be maintained by the core. We will register some common metadata structures
in core and some media specific info for audio/video/text in -base. Plugins can
register additional custom metadata.

Along with the metadata description we will have functions to initialize/free (and/or refcount)
a specific GstBufferMeta instance. We also have the possibility to add a custom subbuffer
function that can be used to modify the metadata when a subbuffer is taken.

We also add serialize and deserialize function for the metadata in case we need special
logic for reading and writing the metadata. This is needed for GDP payloading of the
metadata.

The purpose of the separate MetaInfo is to not have to carry the free/init functions in
each buffer instance but to define them globally. We still want quick access to the info
so we need to make the buffer metadata point to the info.

Technically we could also specify the field and types in the MetaInfo and
provide a generic API to retrieve the metadata fields without the need for a
header file. We will not do this yet.
 
The complete buffer with metadata would then look as follows:

                         +-------------------------------------+
GstMiniObject            |     GType (GstBuffer)               |
                         |     refcount, flags, copy/free      |
                         +-------------------------------------+
GstBuffer                |     caps, parent, subfunc           |
                         +.....................................+
                      +- |     info                           ------> GstBufferMetaInfo
GstBufferMetaTiming   |  |     next                           ---+
                      |  |                                     | |
                      |  |     dts                             | |
                      |  |     pts                             | |
                      |  |     duration                        | |
                      +- |     clock_rate                      | |
                         + . . . . . . . . . . . . . . . . . . + |
                      +- |     info                           <--+ -> GstBufferMetaInfo
GstBufferMetaMemory   |  |     next                           ---+
                      |  |                                     | |
                      |  |     data                            | |
                      |  |     size                            | |
                      |  |     mallocdata                      | |
                      |  |     data_free                       | |
                      +- |     data_user                       | |
                         + . . . . . . . . . . . . . . . . . . + .
                         .                                       .

API examples
------------

Buffers are created using the normal gst_buffer_new functions. The standard fields
are initialized as usual. A memory area that is bigger than the structure size
is allocated for the buffer metadata. The remaining free area is stored in the
free_size field.

  gst_buffer_new ();

After creating a buffer, the application can set caps. and add other metadata
information. 

In order to modify metadata, a reference to the MetaInfo should be obtained.
This can be done like this:

  GstBufferMetaInfo *info;

  info = gst_buffer_meta_get_info (GQuark tag);

Usually the info will be obtained only once in order to avoid lock contention on
the global pool of meta info. The core will also provide convenience functions
for the core metainfo.

Once a reference to the info has been obtained, the associated metadata can be
added or modified on a buffer.

For example, to modify the timing info on a buffer, one could use the following
sequence:

  GstBufferMetaInfo *info;
  GstBufferMetaTiming *timing;

  info = gst_buffer_meta_get_info (GST_META_TIMING_QUARK);
  
  timing = gst_buffer_get_meta (buffer, info, TRUE); /* TRUE = create if absent */
  timing->timestamp = 0;
  timing->duration = 20 * GST_MSECOND;

The _get_meta() function returns a pointer to the metadata structure associated
with the GST_META_TIMING_QUARK info.

For the core meta info, we will provide convenience code that uses the cached
GstBufferMetaInfo, making the above code a little more simple.

  GstBufferMetaTiming *timing;

  timing = gst_buffer_get_meta_timing (buffer, TRUE); /* TRUE = create if absent */
  timing->timestamp = 0;
  timing->duration = 20 * GST_MSECOND;
 
Note that for each of the metadata that we will add to buffers, we need a struct
definition and a registered MetaInfo. 


We will also provide an API to iterate the different metainfo structures. A
possible simple API would look like this:

 GstBufferMeta *current = NULL;

 /* passing NULL gives the first entry */ 
 current = gst_buffer_meta_get_next (buffer, current);

 /* passing a GstBufferMeta returns the next */
 current = gst_buffer_meta_get_next (buffer, current);



Memory management
-----------------

* allocation

  We will initially allocate a reasonable sized GstBuffer structure (say 512
  bytes) and we will set the free_size to the maximum amount of metadata we can
  store.

  Since the complete buffer structure, including a large area for metadata, is
  allocated in one go, we can reduce the number of memory allocations while still
  providing dynamic metadata.

  When adding metadata, we need to call the init function of the associated
  metadata info structure. Since adding the metadata requires the caller to pass
  a handle to the info, this operation does not require table lookups.

  Per-metadata memory initialisation is needed because not all metadata is
  initialized in the same way. We need to, for example, set the timestamps to
  NONE in the MetaTiming structures.

  The init/free functions can also be used to implement refcounting for a metadata
  structure. This can be useful is a structure is shared between buffers.

  When the free_size of the GstBuffer is exhausted, we will allocate new memory
  for each newly added BufferMeta and use the next pointers to point to this. It
  is expected that this does not occur often and we might be able to optimize
  this transparently in the future.

* free

  When a GstBuffer is freed, we potentially might have to call a custom free
  function on the metadata info. In the case of the Memory metadata, we need to
  call the associated free function to free the memory.
  
  When freeing a GstBuffer, the custom buffer free function will iterate all of
  the metadata in the buffer and call the associated free functions in the
  MetaInfo associated with the entries. Usually, this function will be NULL.


Subbufers
---------

Subbuffers are a first class feature of the GstBuffer. 

Creating a subbuffer from a GstBuffer will allocate a new GstBuffer and ref the
parent buffer. It will then iterate all of the metadata entries for the parent
buffer and call the associated sub_func in the MetaInfo.

This allows each metadata structure to implement the actions needed to update
the metadata of the subbuffer. 

A pointer to the old and new memory location of the metadata is passed to the
sub_func. The default implementation will simply copy the metadata. Custom
implementations can adjust the values. For example, when making a subbuffer, the
timing metadata needs to be reset to NONE when the start offset is different.


Serialization
-------------

When buffer should be sent over the wire or be serialized in GDP, we need a way
to perform custom serialization and deserialization on the metadata.

For this we add the serialize and deserialize functions to the metadata info.
Possible use cases are to make sure we write out the fields with a specific size
and endianness.


Other use cases
---------------

Making the GstBufferMetaMemory (for making the buffer point to the associated
memory region) as metadata on a GstBuffer, as opposed to making it an integral
part of GstBuffer, allows for some more interesting ways to transfer data.

We could for example make a new GstBufferMetaIOVec metadata structure like this:

  struct _GstBufferMetaIOVec {
    GstBufferMeta  meta;
   
    /* pointer to data and its size */
    GFreeFunc       data_free;
    gpointer        data_user;
    guint           len;
    struct iovec   *iov;
  };

This would allow us to transfer data in a scatter/gather array. Since the fields
in the buffer metadata are now explicit, elements that don't support this kind
of metadata can gracefully degrade.

Another use case for not having the Memory metadata in the buffers would be for
_pad_alloc() and get_range(). We can pass a GstBuffer with the requested
metadata fields to those functions and have the _get_range() or pad_alloc()
implementations add (or use, in the case of a file reader) the memory metadata. 


Relationship with GstCaps
-------------------------

The difference between GstCaps, used in negotiation, and the metadata is not
clearly defined. 

We would like to think of the GstCaps containing the information needed to
functionally negotiate the format between two elements. The Metadata should then
only contain variables that can change between each buffer.