2012-10-01 11:28:54 +00:00
|
|
|
<chapter id="chapter-allocation" xreflabel="Memory allocation">
|
|
|
|
<title>Memory allocation</title>
|
|
|
|
<para>
|
|
|
|
Memory allocation and management is a very important topic in
|
2014-10-08 14:03:20 +00:00
|
|
|
multimedia. High definition video uses many megabytes to store
|
2012-10-01 11:28:54 +00:00
|
|
|
one single frame of video. It is important to reuse the memory
|
|
|
|
when possible instead of constantly allocating and freeing
|
|
|
|
the memory.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
Multimedia systems usually use special purpose chips, such as
|
|
|
|
DSPs or GPUs to perform the heavy lifting (especially for video).
|
|
|
|
These special purpose chips have usually strict requirements
|
|
|
|
for the memory that they can operate on and how the memory
|
|
|
|
is accessed.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
This chapter talks about the memory management features that
|
|
|
|
&GStreamer; plugins can use. We will first talk about the
|
|
|
|
lowlevel <classname>GstMemory</classname> object that manages
|
|
|
|
access to a piece of memory. We then continue with
|
|
|
|
<classname>GstBuffer</classname> that is used to exchange data
|
|
|
|
between plugins (and the application) and that uses
|
|
|
|
<classname>GstMemory</classname>. We talk about
|
|
|
|
<classname>GstMeta</classname> that can be placed on buffers to
|
|
|
|
give extra info about the buffer and its memory.
|
|
|
|
For efficiently managing buffers of the same size, we take a
|
|
|
|
look at <classname>GstBufferPool</classname>. To conclude this
|
|
|
|
chapter we take a look at the GST_QUERY_ALLOCATION query that
|
|
|
|
is used to negotiate memory management options between elements.
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<sect1 id="section-allocation-memory" xreflabel="GstMemory">
|
|
|
|
<title>GstMemory</title>
|
|
|
|
<para>
|
2012-10-01 14:55:55 +00:00
|
|
|
<classname>GstMemory</classname> is an object that manages a region
|
|
|
|
of memory. The memory object points to a region of memory of
|
|
|
|
<quote>maxsize</quote>. The area in this memory starting at
|
|
|
|
<quote>offset</quote> and for <quote>size</quote> bytes is the
|
|
|
|
accessible region in the memory. the maxsize of the memory can
|
|
|
|
never be changed after the object is created, however, the offset
|
|
|
|
and size can be changed.
|
|
|
|
</para>
|
2013-04-27 18:33:06 +00:00
|
|
|
<sect2 id="section-allocation-allocator" xreflabel="GstAllocator">
|
|
|
|
<title>GstAllocator</title>
|
|
|
|
<para>
|
|
|
|
<classname>GstMemory</classname> objects are created by a
|
|
|
|
<classname>GstAllocator</classname> object. Most allocators implement the
|
|
|
|
default <function>gst_allocator_alloc()</function> method but some allocator
|
|
|
|
might implement a different method, for example when additional parameters
|
|
|
|
are needed to allocate the specific memory.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
Different allocators exist for, for example, system memory, shared memory
|
|
|
|
and memory backed by a DMAbuf file descriptor. To implement support for a
|
|
|
|
new kind of memory type, you must implement a new allocator object as shown
|
|
|
|
below.
|
|
|
|
</para>
|
|
|
|
</sect2>
|
2012-10-02 09:34:47 +00:00
|
|
|
<sect2 id="section-allocation-memory-ex" xreflabel="GstMemory-ex">
|
|
|
|
<title>GstMemory API example</title>
|
|
|
|
<para>
|
|
|
|
Data access to the memory wrapped by the <classname>GstMemory</classname>
|
|
|
|
object is always protected with a <function>gst_memory_map()</function>
|
|
|
|
and <function>gst_memory_unmap()</function> pair. An access mode
|
|
|
|
(read/write) must be given when mapping memory. The map
|
|
|
|
function returns a pointer to the valid memory region that can
|
|
|
|
then be accessed according to the requested access mode.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
Below is an example of making a <classname>GstMemory</classname>
|
|
|
|
object and using the <function>gst_memory_map()</function> to
|
|
|
|
access the memory region.
|
|
|
|
</para>
|
|
|
|
<programlisting>
|
|
|
|
<![CDATA[
|
|
|
|
[...]
|
|
|
|
|
|
|
|
GstMemory *mem;
|
|
|
|
GstMapInfo info;
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
/* allocate 100 bytes */
|
|
|
|
mem = gst_allocator_alloc (NULL, 100, NULL);
|
|
|
|
|
|
|
|
/* get access to the memory in write mode */
|
|
|
|
gst_memory_map (mem, &info, GST_MAP_WRITE);
|
|
|
|
|
|
|
|
/* fill with pattern */
|
|
|
|
for (i = 0; i < info.size; i++)
|
|
|
|
info.data[i] = i;
|
|
|
|
|
|
|
|
/* release memory */
|
|
|
|
gst_memory_unmap (mem, &info);
|
|
|
|
|
|
|
|
[...]
|
|
|
|
]]>
|
|
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
|
2013-04-27 18:33:06 +00:00
|
|
|
<sect2 id="section-allocation-allocator-ex" xreflabel="GstAllocator-ex">
|
2012-10-02 09:34:47 +00:00
|
|
|
<title>Implementing a GstAllocator</title>
|
|
|
|
<para>
|
|
|
|
WRITEME
|
|
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
|
2012-10-01 11:28:54 +00:00
|
|
|
</sect1>
|
|
|
|
|
|
|
|
<sect1 id="section-allocation-buffer" xreflabel="GstBuffer">
|
|
|
|
<title>GstBuffer</title>
|
|
|
|
<para>
|
2012-10-01 14:55:55 +00:00
|
|
|
A <classname>GstBuffer</classname> is an lightweight object that
|
|
|
|
is passed from an upstream to a downstream element and contains
|
|
|
|
memory and metadata. It represents the multimedia content that
|
|
|
|
is pushed or pull downstream by elements.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
The buffer contains one or more <classname>GstMemory</classname>
|
2014-10-16 08:55:36 +00:00
|
|
|
objects that represent the data in the buffer.
|
2012-10-01 14:55:55 +00:00
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
Metadata in the buffer consists of:
|
|
|
|
</para>
|
|
|
|
<itemizedlist mark="opencircle">
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
DTS and PTS timestamps. These represent the decoding and
|
|
|
|
presentation timestamps of the buffer content and is used by
|
|
|
|
synchronizing elements to schedule buffers. Both these timestamps
|
|
|
|
can be GST_CLOCK_TIME_NONE when unknown/undefined.
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
The duration of the buffer contents. This duration can be
|
|
|
|
GST_CLOCK_TIME_NONE when unknown/undefined.
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
Media specific offsets and offset_end. For video this is the
|
|
|
|
frame number in the stream and for audio the sample number. Other
|
|
|
|
definitions for other media exist.
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
Arbitrary structures via <classname>GstMeta</classname>, see below.
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
2012-10-02 09:34:47 +00:00
|
|
|
|
|
|
|
<sect2 id="section-allocation-writability" xreflabel="GstBuffer-write">
|
|
|
|
<title>GstBuffer writability</title>
|
|
|
|
<para>
|
|
|
|
A buffer is writable when the refcount of the object is exactly 1, meaning
|
|
|
|
that only one object is holding a ref to the buffer. You can only
|
|
|
|
modify anything in the buffer when the buffer is writable. This means
|
|
|
|
that you need to call <function>gst_buffer_make_writable()</function>
|
|
|
|
before changing the timestamps, offsets, metadata or adding and
|
|
|
|
removing memory blocks.
|
|
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="section-allocation-buffer-ex" xreflabel="GstBuffer-ex">
|
|
|
|
<title>GstBuffer API examples</title>
|
|
|
|
<para>
|
|
|
|
You can create a buffer with <function>gst_buffer_new ()</function>
|
|
|
|
and then add memory objects to it or you can use a convenience function
|
|
|
|
<function>gst_buffer_new_allocate ()</function> which combines the
|
|
|
|
two. It's also possible to wrap existing memory with
|
|
|
|
<function>gst_buffer_new_wrapped_full () </function> where you can
|
|
|
|
give the function to call when the memory should be freed.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
You can access the memory of the buffer by getting and mapping the
|
|
|
|
<classname>GstMemory</classname> objects individually or by using
|
|
|
|
<function>gst_buffer_map ()</function>. The latter merges all the
|
|
|
|
memory into one big block and then gives you a pointer to this block.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
Below is an example of how to create a buffer and access its memory.
|
|
|
|
</para>
|
|
|
|
<programlisting>
|
|
|
|
<![CDATA[
|
|
|
|
[...]
|
|
|
|
GstBuffer *buffer;
|
|
|
|
GstMemory *mem;
|
|
|
|
GstMapInfo info;
|
|
|
|
|
|
|
|
/* make empty buffer */
|
|
|
|
buffer = gst_buffer_new ();
|
|
|
|
|
|
|
|
/* make memory holding 100 bytes */
|
|
|
|
mem = gst_allocator_alloc (NULL, 100, NULL);
|
|
|
|
|
2013-05-31 22:37:07 +00:00
|
|
|
/* add the buffer */
|
2012-10-02 09:34:47 +00:00
|
|
|
gst_buffer_append_memory (buffer, mem);
|
|
|
|
|
|
|
|
[...]
|
|
|
|
|
|
|
|
/* get WRITE access to the memory and fill with 0xff */
|
|
|
|
gst_buffer_map (buffer, &info, GST_MAP_WRITE);
|
|
|
|
memset (info.data, 0xff, info.size);
|
|
|
|
gst_buffer_unmap (buffer, &info);
|
|
|
|
|
|
|
|
[...]
|
|
|
|
|
|
|
|
/* free the buffer */
|
|
|
|
gst_buffer_unref (buffer);
|
|
|
|
|
|
|
|
[...]
|
|
|
|
]]>
|
|
|
|
</programlisting>
|
|
|
|
</sect2>
|
2012-10-01 11:28:54 +00:00
|
|
|
</sect1>
|
|
|
|
|
|
|
|
<sect1 id="section-allocation-meta" xreflabel="GstMeta">
|
|
|
|
<title>GstMeta</title>
|
|
|
|
<para>
|
2012-10-01 14:55:55 +00:00
|
|
|
With the <classname>GstMeta</classname> system you can add arbitrary
|
2013-04-27 18:33:06 +00:00
|
|
|
structures on buffers. These structures describe extra properties
|
2012-10-01 14:55:55 +00:00
|
|
|
of the buffer such as cropping, stride, region of interest etc.
|
|
|
|
</para>
|
2012-10-02 09:34:47 +00:00
|
|
|
<para>
|
|
|
|
The metadata system separates API specification (what the metadata
|
|
|
|
and its API look like) and the implementation (how it works). This makes
|
|
|
|
it possible to make different implementations of the same API,
|
|
|
|
for example, depending on the hardware you are running on.
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<sect2 id="section-allocation-meta-ex" xreflabel="GstMeta-ex">
|
|
|
|
<title>GstMeta API example</title>
|
|
|
|
<para>
|
|
|
|
After allocating a new buffer, you can add metadata to the buffer
|
|
|
|
with the metadata specific API. This means that you will need to
|
|
|
|
link to the header file where the metadata is defined to use
|
|
|
|
its API.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
By convention, a metadata API with name <classname>FooBar</classname>
|
|
|
|
should provide two methods, a
|
|
|
|
<function>gst_buffer_add_foo_bar_meta ()</function> and a
|
|
|
|
<function>gst_buffer_get_foo_bar_meta ()</function>. Both functions
|
|
|
|
should return a pointer to a <classname>FooBarMeta</classname>
|
|
|
|
structure that contains the metadata fields. Some of the
|
|
|
|
<function>_add_*_meta ()</function> can have extra parameters that
|
|
|
|
will usually be used to configure the metadata structure for you.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
Let's have a look at the metadata that is used to specify a cropping
|
|
|
|
region for video frames.
|
|
|
|
</para>
|
|
|
|
<programlisting>
|
|
|
|
<![CDATA[
|
|
|
|
#include <gst/video/gstvideometa.h>
|
|
|
|
|
|
|
|
[...]
|
|
|
|
GstVideoCropMeta *meta;
|
|
|
|
|
|
|
|
/* buffer points to a video frame, add some cropping metadata */
|
|
|
|
meta = gst_buffer_add_video_crop_meta (buffer);
|
|
|
|
|
|
|
|
/* configure the cropping metadata */
|
|
|
|
meta->x = 8;
|
|
|
|
meta->y = 8;
|
|
|
|
meta->width = 120;
|
|
|
|
meta->height = 80;
|
|
|
|
[...]
|
|
|
|
]]>
|
|
|
|
</programlisting>
|
|
|
|
<para>
|
|
|
|
An element can then use the metadata on the buffer when rendering
|
|
|
|
the frame like this:
|
|
|
|
</para>
|
|
|
|
<programlisting>
|
|
|
|
<![CDATA[
|
|
|
|
#include <gst/video/gstvideometa.h>
|
|
|
|
|
|
|
|
[...]
|
|
|
|
GstVideoCropMeta *meta;
|
|
|
|
|
|
|
|
/* buffer points to a video frame, get the cropping metadata */
|
|
|
|
meta = gst_buffer_get_video_crop_meta (buffer);
|
|
|
|
|
|
|
|
if (meta) {
|
|
|
|
/* render frame with cropping */
|
|
|
|
_render_frame_cropped (buffer, meta->x, meta->y, meta->width, meta->height);
|
|
|
|
} else {
|
|
|
|
/* render frame */
|
|
|
|
_render_frame (buffer);
|
|
|
|
}
|
|
|
|
[...]
|
|
|
|
|
|
|
|
]]>
|
|
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
<sect2 id="section-allocation-meta-new" xreflabel="GstMeta-new">
|
|
|
|
<title>Implementing new GstMeta</title>
|
|
|
|
<para>
|
|
|
|
In the next sections we show how you can add new metadata to the
|
|
|
|
system and use it on buffers.
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<sect3 id="section-allocation-meta-api" xreflabel="GstMeta-api">
|
|
|
|
<title>Define the metadata API</title>
|
|
|
|
<para>
|
|
|
|
First we need to define what our API will look like and we
|
|
|
|
will have to register this API to the system. This is important
|
|
|
|
because this API definition will be used when elements negotiate
|
|
|
|
what kind of metadata they will exchange. The API definition
|
|
|
|
also contains arbitrary tags that give hints about what the
|
|
|
|
metadata contains. This is important when we see how metadata
|
|
|
|
is preserved when buffers pass through the pipeline.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
If you are making a new implementation of an existing API,
|
|
|
|
you can skip this step and move on to the implementation step.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
First we start with making the
|
|
|
|
<filename>my-example-meta.h</filename> header file that will contain
|
|
|
|
the definition of the API and structure for our metadata.
|
|
|
|
</para>
|
|
|
|
<programlisting>
|
|
|
|
<![CDATA[
|
|
|
|
#include <gst/gst.h>
|
|
|
|
|
|
|
|
typedef struct _MyExampleMeta MyExampleMeta;
|
|
|
|
|
|
|
|
struct _MyExampleMeta {
|
|
|
|
GstMeta meta;
|
|
|
|
|
|
|
|
gint age;
|
|
|
|
gchar *name;
|
|
|
|
};
|
|
|
|
|
|
|
|
GType my_example_meta_api_get_type (void);
|
|
|
|
#define MY_EXAMPLE_META_API_TYPE (my_example_meta_api_get_type())
|
|
|
|
|
|
|
|
#define gst_buffer_get_my_example_meta(b) \
|
|
|
|
((MyExampleMeta*)gst_buffer_get_meta((b),MY_EXAMPLE_META_API_TYPE))
|
|
|
|
]]>
|
|
|
|
</programlisting>
|
|
|
|
<para>
|
|
|
|
The metadata API definition consists of the definition of the
|
|
|
|
structure that holds a gint and a string. The first field in
|
|
|
|
the structure must be <classname>GstMeta</classname>.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
We also define a <function>my_example_meta_api_get_type ()</function>
|
|
|
|
function that will register out metadata API definition. We
|
|
|
|
also define a convenience macro
|
|
|
|
<function>gst_buffer_get_my_example_meta ()</function> that simply
|
|
|
|
finds and returns the metadata with our new API.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
Next let's have a look at how the
|
|
|
|
<function>my_example_meta_api_get_type ()</function> function is
|
|
|
|
implemented in the <filename>my-example-meta.c</filename> file.
|
|
|
|
</para>
|
|
|
|
<programlisting>
|
|
|
|
<![CDATA[
|
|
|
|
#include "my-example-meta.h"
|
|
|
|
|
|
|
|
GType
|
|
|
|
my_example_meta_api_get_type (void)
|
|
|
|
{
|
|
|
|
static volatile GType type;
|
|
|
|
static const gchar *tags[] = { "foo", "bar", NULL };
|
|
|
|
|
|
|
|
if (g_once_init_enter (&type)) {
|
|
|
|
GType _type = gst_meta_api_type_register ("MyExampleMetaAPI", tags);
|
|
|
|
g_once_init_leave (&type, _type);
|
|
|
|
}
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
]]>
|
|
|
|
</programlisting>
|
|
|
|
<para>
|
|
|
|
As you can see, it simply uses the
|
|
|
|
<function>gst_meta_api_type_register ()</function> function to
|
|
|
|
register a name for the api and some tags. The result is a
|
|
|
|
new pointer GType that defines the newly registered API.
|
|
|
|
</para>
|
|
|
|
</sect3>
|
|
|
|
|
|
|
|
<sect3 id="section-allocation-meta-impl" xreflabel="GstMeta-impl">
|
|
|
|
<title>Implementing a metadata API</title>
|
|
|
|
<para>
|
|
|
|
Next we can make an implementation for a registered metadata
|
|
|
|
API GType. The implementation detail of a metadata API
|
|
|
|
are kept in a <classname>GstMetaInfo</classname> structure
|
|
|
|
that you will make available to the users of your metadata
|
|
|
|
API implementation with a <function>my_example_meta_get_info ()</function>
|
|
|
|
function and a convenience <function>MY_EXAMPLE_META_INFO</function>
|
|
|
|
macro. You will also make a method to add your metadata
|
|
|
|
implementation to a <classname>GstBuffer</classname>.
|
|
|
|
Your <filename>my-example-meta.h</filename> header file will
|
2014-10-16 08:55:36 +00:00
|
|
|
need these additions:
|
2012-10-02 09:34:47 +00:00
|
|
|
</para>
|
|
|
|
<programlisting>
|
|
|
|
<![CDATA[
|
|
|
|
[...]
|
|
|
|
|
|
|
|
/* implementation */
|
|
|
|
const GstMetaInfo *my_example_meta_get_info (void);
|
|
|
|
#define MY_EXAMPLE_META_INFO (my_example_meta_get_info())
|
|
|
|
|
|
|
|
MyExampleMeta * gst_buffer_add_my_example_meta (GstBuffer *buffer,
|
|
|
|
gint age,
|
|
|
|
const gchar *name);
|
|
|
|
]]>
|
|
|
|
</programlisting>
|
|
|
|
<para>
|
|
|
|
Let's have a look at how these functions are
|
|
|
|
implemented in the <filename>my-example-meta.c</filename> file.
|
|
|
|
</para>
|
|
|
|
<programlisting>
|
|
|
|
<![CDATA[
|
|
|
|
[...]
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
my_example_meta_init (GstMeta * meta, gpointer params, GstBuffer * buffer)
|
|
|
|
{
|
|
|
|
MyExampleMeta *emeta = (MyExampleMeta *) meta;
|
|
|
|
|
|
|
|
emeta->age = 0;
|
|
|
|
emeta->name = NULL;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
my_example_meta_transform (GstBuffer * transbuf, GstMeta * meta,
|
|
|
|
GstBuffer * buffer, GQuark type, gpointer data)
|
|
|
|
{
|
|
|
|
MyExampleMeta *emeta = (MyExampleMeta *) meta;
|
|
|
|
|
|
|
|
/* we always copy no matter what transform */
|
|
|
|
gst_buffer_add_my_example_meta (transbuf, emeta->age, emeta->name);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
my_example_meta_free (GstMeta * meta, GstBuffer * buffer)
|
|
|
|
{
|
|
|
|
MyExampleMeta *emeta = (MyExampleMeta *) meta;
|
|
|
|
|
2016-02-02 16:34:51 +00:00
|
|
|
g_free (emeta->name);
|
2012-10-02 09:34:47 +00:00
|
|
|
emeta->name = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
const GstMetaInfo *
|
|
|
|
my_example_meta_get_info (void)
|
|
|
|
{
|
|
|
|
static const GstMetaInfo *meta_info = NULL;
|
|
|
|
|
2012-10-03 11:45:22 +00:00
|
|
|
if (g_once_init_enter (&meta_info)) {
|
|
|
|
const GstMetaInfo *mi = gst_meta_register (MY_EXAMPLE_META_API_TYPE,
|
2012-10-02 09:34:47 +00:00
|
|
|
"MyExampleMeta",
|
|
|
|
sizeof (MyExampleMeta),
|
|
|
|
my_example_meta_init,
|
|
|
|
my_example_meta_free,
|
|
|
|
my_example_meta_transform);
|
2012-10-03 11:45:22 +00:00
|
|
|
g_once_init_leave (&meta_info, mi);
|
2012-10-02 09:34:47 +00:00
|
|
|
}
|
|
|
|
return meta_info;
|
|
|
|
}
|
|
|
|
|
|
|
|
MyExampleMeta *
|
|
|
|
gst_buffer_add_my_example_meta (GstBuffer *buffer,
|
|
|
|
gint age,
|
|
|
|
const gchar *name)
|
|
|
|
{
|
|
|
|
MyExampleMeta *meta;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
|
|
|
|
|
|
|
|
meta = (MyExampleMeta *) gst_buffer_add_meta (buffer,
|
|
|
|
MY_EXAMPLE_META_INFO, NULL);
|
|
|
|
|
|
|
|
meta->age = age;
|
|
|
|
meta->name = g_strdup (name);
|
|
|
|
|
|
|
|
return meta;
|
|
|
|
}
|
|
|
|
]]>
|
|
|
|
</programlisting>
|
|
|
|
<para>
|
|
|
|
<function>gst_meta_register ()</function> registers the implementation
|
|
|
|
details, like the API that you implement and the size of the
|
|
|
|
metadata structure along with methods to initialize and free the
|
|
|
|
memory area. You can also implement a transform function that will
|
|
|
|
be called when a certain transformation (identified by the quark and
|
|
|
|
quark specific data) is performed on a buffer.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
Lastly, you implement a <function>gst_buffer_add_*_meta()</function>
|
|
|
|
that adds the metadata implementation to a buffer and sets the
|
|
|
|
values of the metadata.
|
|
|
|
</para>
|
|
|
|
</sect3>
|
|
|
|
</sect2>
|
|
|
|
|
2012-10-01 11:28:54 +00:00
|
|
|
</sect1>
|
|
|
|
|
|
|
|
<sect1 id="section-allocation-bufferpool" xreflabel="GstBufferPool">
|
|
|
|
<title>GstBufferPool</title>
|
|
|
|
<para>
|
2012-10-01 14:55:55 +00:00
|
|
|
The <classname>GstBufferPool</classname> object provides a convenient
|
|
|
|
base class for managing lists of reusable buffers. Essential for this
|
|
|
|
object is that all the buffers have the same properties such as size,
|
|
|
|
padding, metadata and alignment.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
A bufferpool object can be configured to manage a minimum and maximum
|
|
|
|
amount of buffers of a specific size. A bufferpool can also be
|
|
|
|
configured to use a specific <classname>GstAllocator</classname> for
|
|
|
|
the memory of the buffers. There is support in the bufferpool to enable
|
|
|
|
bufferpool specific options, such as adding <classname>GstMeta</classname>
|
|
|
|
to the buffers in the pool or such as enabling specific padding on
|
|
|
|
the memory in the buffers.
|
2012-10-01 11:28:54 +00:00
|
|
|
</para>
|
2012-10-02 10:49:17 +00:00
|
|
|
<para>
|
|
|
|
A Bufferpool can be inactivate and active. In the inactive state,
|
|
|
|
you can configure the pool. In the active state, you can't change
|
|
|
|
the configuration anymore but you can acquire and release buffers
|
|
|
|
from/to the pool.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
In the following sections we take a look at how you can use
|
|
|
|
a bufferpool.
|
|
|
|
</para>
|
2012-10-02 09:34:47 +00:00
|
|
|
|
|
|
|
<sect2 id="section-allocation-pool-ex" xreflabel="GstBufferPool-ex">
|
|
|
|
<title>GstBufferPool API example</title>
|
|
|
|
<para>
|
2012-10-02 10:49:17 +00:00
|
|
|
Many different bufferpool implementations can exist; they are all
|
|
|
|
subclasses of the base class <classname>GstBufferPool</classname>.
|
|
|
|
For this example, we will assume we somehow have access to a
|
|
|
|
bufferpool, either because we created it ourselves or because
|
|
|
|
we were given one as a result of the ALLOCATION query as we will
|
|
|
|
see below.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
The bufferpool is initially in the inactive state so that we can
|
|
|
|
configure it. Trying to configure a bufferpool that is not in the
|
|
|
|
inactive state will fail. Likewise, trying to activate a bufferpool
|
|
|
|
that is not configured will fail.
|
|
|
|
</para>
|
|
|
|
<programlisting>
|
|
|
|
<![CDATA[
|
|
|
|
GstStructure *config;
|
|
|
|
|
|
|
|
[...]
|
|
|
|
|
|
|
|
/* get config structure */
|
|
|
|
config = gst_buffer_pool_get_config (pool);
|
|
|
|
|
|
|
|
/* set caps, size, minimum and maximum buffers in the pool */
|
|
|
|
gst_buffer_pool_config_set_params (config, caps, size, min, max);
|
|
|
|
|
|
|
|
/* configure allocator and parameters */
|
|
|
|
gst_buffer_pool_config_set_allocator (config, allocator, ¶ms);
|
|
|
|
|
|
|
|
/* store the updated configuration again */
|
|
|
|
gst_buffer_pool_set_config (pool, config);
|
|
|
|
|
|
|
|
[...]
|
|
|
|
]]>
|
|
|
|
</programlisting>
|
|
|
|
<para>
|
|
|
|
The configuration of the bufferpool is maintained in a generic
|
|
|
|
<classname>GstStructure</classname> that can be obtained with
|
|
|
|
<function>gst_buffer_pool_get_config()</function>. Convenience
|
|
|
|
methods exist to get and set the configuration options in this
|
|
|
|
structure. After updating the structure, it is set as the current
|
|
|
|
configuration in the bufferpool again with
|
|
|
|
<function>gst_buffer_pool_set_config()</function>.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
The following options can be configured on a bufferpool:
|
|
|
|
</para>
|
|
|
|
<itemizedlist mark="opencircle">
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
The caps of the buffers to allocate.
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
The size of the buffers. This is the suggested size of the
|
|
|
|
buffers in the pool. The pool might decide to allocate larger
|
|
|
|
buffers to add padding.
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
The minimum and maximum amount of buffers in the pool. When
|
|
|
|
minimum is set to > 0, the bufferpool will pre-allocate this
|
|
|
|
amount of buffers. When maximum is not 0, the bufferpool
|
|
|
|
will allocate up to maximum amount of buffers.
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
The allocator and parameters to use. Some bufferpools might
|
|
|
|
ignore the allocator and use its internal one.
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
Other arbitrary bufferpool options identified with a string.
|
|
|
|
a bufferpool lists the supported options with
|
|
|
|
<function>gst_buffer_pool_get_options()</function> and you
|
|
|
|
can ask if an option is supported with
|
|
|
|
<function>gst_buffer_pool_has_option()</function>. The option
|
|
|
|
can be enabled by adding it to the configuration structure
|
|
|
|
with <function>gst_buffer_pool_config_add_option ()</function>.
|
|
|
|
These options are used to enable things like letting the
|
|
|
|
pool set metadata on the buffers or to add extra configuration
|
|
|
|
options for padding, for example.
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
|
|
After the configuration is set on the bufferpool, the pool can
|
|
|
|
be activated with
|
|
|
|
<function>gst_buffer_pool_set_active (pool, TRUE)</function>. From
|
|
|
|
that point on you can use
|
|
|
|
<function>gst_buffer_pool_acquire_buffer ()</function> to retrieve
|
|
|
|
a buffer from the pool, like this:
|
|
|
|
</para>
|
|
|
|
<programlisting>
|
|
|
|
<![CDATA[
|
|
|
|
[...]
|
|
|
|
|
|
|
|
GstFlowReturn ret;
|
|
|
|
GstBuffer *buffer;
|
|
|
|
|
|
|
|
ret = gst_buffer_pool_acquire_buffer (pool, &buffer, NULL);
|
|
|
|
if (G_UNLIKELY (ret != GST_FLOW_OK))
|
|
|
|
goto pool_failed;
|
|
|
|
|
|
|
|
[...]
|
|
|
|
]]>
|
|
|
|
</programlisting>
|
|
|
|
<para>
|
|
|
|
It is important to check the return value of the acquire function
|
|
|
|
because it is possible that it fails: When your
|
|
|
|
element shuts down, it will deactivate the bufferpool and then
|
|
|
|
all calls to acquire will return GST_FLOW_FLUSHNG.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
All buffers that are acquired from the pool will have their pool
|
|
|
|
member set to the original pool. When the last ref is decremented
|
|
|
|
on the buffer, &GStreamer; will automatically call
|
|
|
|
<function>gst_buffer_pool_release_buffer()</function> to release
|
|
|
|
the buffer back to the pool. You (or any other downstream element)
|
|
|
|
don't need to know if a buffer came from a pool, you can just
|
|
|
|
unref it.
|
2012-10-02 09:34:47 +00:00
|
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
|
2012-10-02 10:49:17 +00:00
|
|
|
<sect2 id="section-allocation-pool-impl" xreflabel="GstBufferPool-impl">
|
2012-10-02 09:34:47 +00:00
|
|
|
<title>Implementing a new GstBufferPool</title>
|
|
|
|
<para>
|
|
|
|
WRITEME
|
|
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
|
2012-10-01 11:28:54 +00:00
|
|
|
</sect1>
|
|
|
|
|
|
|
|
<sect1 id="section-allocation-query" xreflabel="GST_QUERY_ALLOCATION">
|
|
|
|
<title>GST_QUERY_ALLOCATION</title>
|
|
|
|
<para>
|
2012-10-01 14:55:55 +00:00
|
|
|
The ALLOCATION query is used to negotiate
|
|
|
|
<classname>GstMeta</classname>, <classname>GstBufferPool</classname>
|
|
|
|
and <classname>GstAllocator</classname> between elements. Negotiation
|
|
|
|
of the allocation strategy is always initiated and decided by a srcpad
|
|
|
|
after it has negotiated a format and before it decides to push buffers.
|
|
|
|
A sinkpad can suggest an allocation strategy but it is ultimately the
|
|
|
|
source pad that will decide based on the suggestions of the downstream
|
|
|
|
sink pad.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
The source pad will do a GST_QUERY_ALLOCATION with the negotiated caps
|
|
|
|
as a parameter. This is needed so that the downstream element knows
|
|
|
|
what media type is being handled. A downstream sink pad can answer the
|
|
|
|
allocation query with the following results:
|
2012-10-01 11:28:54 +00:00
|
|
|
</para>
|
2012-10-01 14:55:55 +00:00
|
|
|
<itemizedlist mark="opencircle">
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
An array of possible <classname>GstBufferPool</classname> suggestions
|
|
|
|
with suggested size, minimum and maximum amount of buffers.
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
An array of GstAllocator objects along with suggested allocation
|
|
|
|
parameters such as flags, prefix, alignment and padding. These
|
|
|
|
allocators can also be configured in a bufferpool when this is
|
|
|
|
supported by the bufferpool.
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
An array of supported <classname>GstMeta</classname> implementations
|
|
|
|
along with metadata specific parameters.
|
|
|
|
It is important that the upstream element knows what kind of
|
|
|
|
metadata is supported downstream before it places that metadata
|
|
|
|
on buffers.
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
|
|
When the GST_QUERY_ALLOCATION returns, the source pad will select
|
|
|
|
from the available bufferpools, allocators and metadata how it will
|
|
|
|
allocate buffers.
|
|
|
|
</para>
|
2012-10-02 09:34:47 +00:00
|
|
|
|
|
|
|
<sect2 id="section-allocation-query-ex" xreflabel="Allocation-ex">
|
|
|
|
<title>ALLOCATION query example</title>
|
|
|
|
<para>
|
2012-10-02 11:12:39 +00:00
|
|
|
Below is an example of the ALLOCATION query.
|
|
|
|
</para>
|
|
|
|
<programlisting>
|
|
|
|
<![CDATA[
|
|
|
|
#include <gst/video/video.h>
|
|
|
|
#include <gst/video/gstvideometa.h>
|
|
|
|
#include <gst/video/gstvideopool.h>
|
|
|
|
|
|
|
|
GstCaps *caps;
|
|
|
|
GstQuery *query;
|
|
|
|
GstStructure *structure;
|
|
|
|
GstBufferPool *pool;
|
|
|
|
GstStructure *config;
|
|
|
|
guint size, min, max;
|
|
|
|
|
|
|
|
[...]
|
|
|
|
|
|
|
|
/* find a pool for the negotiated caps now */
|
|
|
|
query = gst_query_new_allocation (caps, TRUE);
|
|
|
|
|
|
|
|
if (!gst_pad_peer_query (scope->srcpad, query)) {
|
|
|
|
/* query failed, not a problem, we use the query defaults */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gst_query_get_n_allocation_pools (query) > 0) {
|
|
|
|
/* we got configuration from our peer, parse them */
|
|
|
|
gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
|
|
|
|
} else {
|
|
|
|
pool = NULL;
|
|
|
|
size = 0;
|
|
|
|
min = max = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pool == NULL) {
|
|
|
|
/* we did not get a pool, make one ourselves then */
|
|
|
|
pool = gst_video_buffer_pool_new ();
|
|
|
|
}
|
|
|
|
|
|
|
|
config = gst_buffer_pool_get_config (pool);
|
|
|
|
gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
|
|
|
|
gst_buffer_pool_config_set_params (config, caps, size, min, max);
|
|
|
|
gst_buffer_pool_set_config (pool, config);
|
|
|
|
|
|
|
|
/* and activate */
|
|
|
|
gst_buffer_pool_set_active (pool, TRUE);
|
|
|
|
|
|
|
|
[...]
|
|
|
|
]]>
|
|
|
|
</programlisting>
|
|
|
|
<para>
|
|
|
|
This particular implementation will make a custom
|
|
|
|
<classname>GstVideoBufferPool</classname> object that is specialized
|
|
|
|
in allocating video buffers. You can also enable the pool to
|
|
|
|
put <classname>GstVideoMeta</classname> metadata on the buffers from
|
|
|
|
the pool doing
|
|
|
|
<function>gst_buffer_pool_config_add_option (config,
|
|
|
|
GST_BUFFER_POOL_OPTION_VIDEO_META)</function>.
|
2012-10-02 09:34:47 +00:00
|
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
<sect2 id="section-allocation-query-base" xreflabel="Allocation-base">
|
|
|
|
<title>The ALLOCATION query in base classes</title>
|
|
|
|
<para>
|
|
|
|
In many baseclasses you will see the following virtual methods for
|
|
|
|
influencing the allocation strategy:
|
|
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
<function>propose_allocation ()</function> should suggest
|
|
|
|
allocation parameters for the upstream element.
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
<function>decide_allocation ()</function> should decide the
|
|
|
|
allocation parameters from the suggestions received from
|
|
|
|
downstream.
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
2012-10-02 11:12:39 +00:00
|
|
|
<para>
|
|
|
|
Implementors of these methods should modify the given
|
|
|
|
<classname>GstQuery</classname> object by updating the pool options
|
|
|
|
and allocation options.
|
|
|
|
</para>
|
2012-10-02 09:34:47 +00:00
|
|
|
</sect2>
|
2012-10-01 11:28:54 +00:00
|
|
|
</sect1>
|
|
|
|
</chapter>
|