gstreamer/docs/design/draft-buffer2.txt

542 lines
19 KiB
Text
Raw Normal View History

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.
2011-02-27 11:21:32 +00:00
- We should be able to negotiate metadata between elements
2010-02-26 12:11:43 +00:00
Use cases
---------
* DSP vs CPU caches
2011-03-04 18:02:33 +00:00
Both DSP and CPU can have separate MMUs and memory caches. When we exchange buffers
2010-02-26 12:11:43 +00:00
between two subsystems we need to flush caches so that one CPU can see the
modifications done by the other CPU. These cashes must only be flushed when one
CPU performed a write and the other CPU needs to do a read.
In order to implement this we need to be able to mark our read and write
operations on the buffer data.
2011-03-04 18:02:33 +00:00
It might also be possible that buffers are not mapped into the address space of
the process normally and that an explicit mmap operation is needed to setup
the mapping tables for the physical memory.
* Video planes
Video data is sometimes allocated in non-contiguous planes for the Y and the UV
data. We need to be able to specify the data on a buffer using multiple
pointers in memory. We also need to be able to specify the stride for these
planes.
* Extra buffer data
Some elements might need to store extra data for a buffer. This is typically
done when the resources are allocated from another subsystem such as OMX or
X11.
* Processing information
Pan and crop information can be added to the buffer data when the downstream
element can understand and use this metadata. An imagesink can, for example,
use the pan and cropping formation when it composites the image on the screen
with little overhead.
2010-02-26 12:11:43 +00:00
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;
2011-02-27 11:21:32 +00:00
gsize size;
GstMiniObjectCopyFunction copy;
2011-02-27 11:21:32 +00:00
GstMiniObjectDisposeFunction dispose;
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;
GstCaps *caps;
GstBuffer *parent;
2011-03-04 18:02:33 +00:00
GstBufferPool *pool;
};
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.
2011-03-04 18:02:33 +00:00
The buffer contains GstMeta items describing the memory is wraps along with
metadata for the timing information etc.
2010-02-26 12:11:43 +00:00
2011-02-27 11:21:32 +00:00
GstMeta
~~~~~~~
2011-02-27 11:21:32 +00:00
A GstMeta is a structure as follows:
2011-02-27 11:21:32 +00:00
struct _GstMeta {
GstMetaInfo *info; /* tag and info for the meta item */
2010-02-26 12:11:43 +00:00
};
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:
2011-02-27 11:21:32 +00:00
struct _GstMetaTiming {
GstMeta 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 */
};
2011-02-27 11:21:32 +00:00
Or another example for the buffer memory region that consists of some methods
only.
2011-02-27 11:21:32 +00:00
struct _GstMetaMemory {
GstMeta meta;
GstMetaMemoryMap mmap_func;
GstMetaMemoryUnmap munmap_func;
};
2011-03-04 18:02:33 +00:00
typedef enum {
GST_BUFFER_MAP_NONE,
GST_BUFFER_MAP_READ,
GST_BUFFER_MAP_WRITE,
} GstBufferMapFlags
2011-02-27 11:21:32 +00:00
gpointer gst_meta_memory_map (GstMetaMemory *, guint offset, guint *size, GstBufferMapFlags);
gboolean gst_meta_memory_unmap (GstMetaMemory *, gpointer data, guint size);
GstMeta derived structures define the API of the metadata. The API can consist of
fields and/or methods. It is possible to have different implementations for the
same GstMeta structure.
The implementation of the GstMeta api would typically add more fields to the
public structure that allow it to implement the API. For example:
struct _GstMetaMemoryImpl {
GstMetaMemory memory;
2010-02-26 12:11:43 +00:00
gpointer *data;
guint size;
2010-02-26 12:11:43 +00:00
gpointer *data_orig;
GFreeFunc data_free;
gpointer data_user;
};
2011-02-27 11:21:32 +00:00
GstMetaInfo will point to more information about the metadata and looks like this:
struct _GstMetaInfo {
GQuark api; /* api name */
GQuark impl; /* implementation name */
gsize size; /* size of the structure */
GstMetaInitFunction init_func;
GstMetaFreeFunction free_func;
GstMetaCopyFunction copy_func;
GstMetaSubFunction sub_func;
GstMetaSerializeFunction serialize_func
GstMetaDeserializeFunction deserialize_func
GstMetaConvFunction conv_func;
2010-02-26 12:11:43 +00:00
};
2011-02-27 11:21:32 +00:00
api will contain a GQuark of the metadata api. 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.
2011-02-27 11:21:32 +00:00
For each implementation of api, there will thus be a unique GstMetaInfo. In the
case of metadata with a well defined API, the implementation specific init
function will setup the methods in the metadata structure.
Along with the metadata description we will have functions to initialize/free (and/or refcount)
2011-02-27 11:21:32 +00:00
a specific GstMeta 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.
We add a conv function to the Info structure that will be called when a buffer
should be converted to an old-style buffer for backward compatibility.
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) |
2011-02-27 11:21:32 +00:00
| refcount, flags, copy/disp/free |
+-------------------------------------+
2011-03-04 18:02:33 +00:00
GstBuffer | caps, parent, pool |
+.....................................+
2010-02-26 12:11:43 +00:00
| next ---+
2011-02-27 11:21:32 +00:00
+- | info ------> GstMetaInfo
GstMetaTiming | | | |
| | dts | |
| | pts | |
| | duration | |
+- | clock_rate | |
+ . . . . . . . . . . . . . . . . . . + |
2010-02-26 12:11:43 +00:00
| next <--+
2011-02-27 11:21:32 +00:00
GstMetaMemory +- +- | info ------> GstMetaInfo
| | | | |
| | | mmap | |
| | | munmap | |
+- | | | |
| | data | |
2011-02-27 11:21:32 +00:00
GstMetaMemoryImpl | | size | |
| | mallocdata | |
| | data_free | |
+- | data_user | |
+ . . . . . . . . . . . . . . . . . . + .
. .
2010-02-26 12:11:43 +00:00
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
2011-02-27 11:21:32 +00:00
is allocated for the buffer metadata.
gst_buffer_new ();
2011-02-27 11:21:32 +00:00
After creating a buffer, the application can set caps and add metadata
information.
2011-02-27 11:21:32 +00:00
To add or retrieve metadata, a handle to a GstMetaInfo structure needs to be
obtained. This defines the implementation and API of the metadata. Usually, a
handle to this info structure can be obtained by callnig a public _get_info()
method from a shared library (for shared metadata).
2011-02-27 11:21:32 +00:00
The following defines can usually be found in the shared .h file.
2011-02-27 11:21:32 +00:00
GstMetaInfo * gst_meta_timing_get_info();
#define GST_META_TIMING_INFO (gst_meta_timing_get_info())
2011-02-27 11:21:32 +00:00
Retrieving and/or creating the metadata on a buffer can be done with the
gst_buffer_meta_get() method. This function retrieves an existing metadata
conforming to the API spcified in the given info. When no such metadata exists
and the last gboolean argument is true, a new metadata item will be created from
the info and added to the buffer.
2011-02-27 11:21:32 +00:00
GstMetaTiming *timing;
2011-02-27 11:21:32 +00:00
timing = gst_buffer_get_meta (buffer, GST_META_TIMING_INFO, TRUE);
2011-02-27 11:21:32 +00:00
Once a reference to the info has been obtained, the associated metadata can be
added or modified on a buffer.
timing->timestamp = 0;
timing->duration = 20 * GST_MSECOND;
2011-02-27 11:21:32 +00:00
Other convenience macros can be made to simplify the above code:
#define gst_buffer_get_meta_timing(b,c) \
((GstMetaTiming *) gst_buffer_get_meta ((b), GST_META_TIMING_INFO, (c))
2011-02-27 11:21:32 +00:00
This makes the code look like this:
2011-02-27 11:21:32 +00:00
GstMetaTiming *timing;
timing = gst_buffer_get_meta_timing (buffer, TRUE); /* TRUE = create if absent */
timing->timestamp = 0;
timing->duration = 20 * GST_MSECOND;
We will also provide an API to iterate the different metainfo structures. A
possible simple API would look like this:
2011-02-27 11:21:32 +00:00
GstMeta *current = NULL;
/* passing NULL gives the first entry */
current = gst_buffer_meta_get_next (buffer, current);
2011-02-27 11:21:32 +00:00
/* passing a GstMeta 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
2011-02-27 11:21:32 +00:00
bytes).
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
2009-11-23 10:33:48 +00:00
structure. This can be useful when a structure is shared between buffers.
When the free_size of the GstBuffer is exhausted, we will allocate new memory
2011-02-27 11:21:32 +00:00
for each newly added Meta 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.
Subbuffers
~~~~~~~~~~
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.
2011-03-04 18:02:33 +00:00
Since the subbuffer expects an offset and size, it might not make sense to make
subbuffers from arbitrary buffers. Video metadata that has data in muliple
planes, for example, might need to copy the planes to its 'natural' contiguous
representation for the subbuffer.
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.
2010-03-31 08:54:55 +00:00
Transformations
~~~~~~~~~~~~~~~
2010-03-31 08:54:55 +00:00
After certain transformations, the metadata on a buffer might not be relevant
anymore.
Consider, for example, metadata that lists certain regions of interest
on the video data. If the video is scaled or rotated, the coordinates might not
make sense anymore. A transform element should be able to adjust or remove the
associated metadata when it becomes invalid.
We can make the transform element aware of the metadata so that it can adjust or
remove in an intelligent way. Since we allow arbitrary metadata, we can't do
this for all metadata and thus we need some other way.
One proposition is to tag the metadata type with keywords that specify what it
functionally refers too. We could, for example, tag the metadata for the regions
of interest with a tag that notes that the metadata refers to absolute pixel
positions. A transform could then know that the metadata is not valid anymore
when the position of the pixels changed (due to rotation, flipping, scaling and
so on).
Other use cases
~~~~~~~~~~~~~~~
2011-02-27 11:21:32 +00:00
Making the GstMetaMemory (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.
2011-02-27 11:21:32 +00:00
We could for example make a new GstMetaIOVec metadata structure like this:
2011-02-27 11:21:32 +00:00
struct _GstMetaIOVec {
GstMeta 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.
2009-12-24 14:13:49 +00:00
For example, for video we would have width/height/framerate in the caps but then
have the more technical details, such as stride, data pointers, pan/crop/zoom
etc in the metadata.
A scheme like this would still allow us to functionally specify the desired
video resolution while the implementation details would be inside the metadata.
2010-03-31 08:54:55 +00:00
Compatibility
~~~~~~~~~~~~~
2010-03-31 08:54:55 +00:00
We need to make sure that elements exchange metadata that they both understand,
This is particulary important when the metadata describes the data layout in
memory (such as strides).
2011-02-27 11:21:32 +00:00
We would like to use the bufferpool negotiation system to negotiate the possible
metadata that can be exchanged between elements.
2010-03-31 08:54:55 +00:00
2011-02-27 11:21:32 +00:00
When deciding the allocation properties, we will also negotiate the buffer
metadata structures that we can exchange.
2010-03-31 08:54:55 +00:00
Notes
~~~~~
2009-12-24 14:13:49 +00:00
Some structures that we need to be able to add to buffers.
* Clean Aperture
* Arbitrary Matrix Transform
* Aspect ratio
* Pan/crop/zoom
* Video strides
2009-12-24 14:13:49 +00:00
Some of these overlap, we need to find a minimal set of metadata structures that
allows us to define all use cases.
2010-02-26 12:11:43 +00:00
Video Buffers
-------------
#define GST_VIDEO_MAX_PLANES 4
struct GstVideoPlane {
guint8 *data;
guint size;
guint stride;
guint8 *data_orig;
guint size_orig;
GFreeFunc data_free;
gpointer data_user;
};
struct GstBufferVideoMeta {
2011-02-27 11:21:32 +00:00
GstMeta meta
2010-02-26 12:11:43 +00:00
GstBufferVideoFlags flags
guint n_planes;
GstVideoPlane plane[GST_VIDEO_MAX_PLANES];
};