| <chapter id="chapter-allocation" xreflabel="Memory allocation"> |
| <title>Memory allocation</title> |
| <para> |
| Memory allocation and management is a very important topic in |
| multimedia. High definition video uses many megabytes to store |
| 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> |
| <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> |
| <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> |
| <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> |
| |
| <sect2 id="section-allocation-allocator-ex" xreflabel="GstAllocator-ex"> |
| <title>Implementing a GstAllocator</title> |
| <para> |
| WRITEME |
| </para> |
| </sect2> |
| |
| </sect1> |
| |
| <sect1 id="section-allocation-buffer" xreflabel="GstBuffer"> |
| <title>GstBuffer</title> |
| <para> |
| 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> |
| objects that represent the data in the buffer. |
| </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> |
| |
| <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); |
| |
| /* add the buffer */ |
| 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> |
| </sect1> |
| |
| <sect1 id="section-allocation-meta" xreflabel="GstMeta"> |
| <title>GstMeta</title> |
| <para> |
| With the <classname>GstMeta</classname> system you can add arbitrary |
| structures on buffers. These structures describe extra properties |
| of the buffer such as cropping, stride, region of interest etc. |
| </para> |
| <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 |
| need these additions: |
| </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; |
| |
| g_free (emeta->name) |
| emeta->name = NULL; |
| } |
| |
| const GstMetaInfo * |
| my_example_meta_get_info (void) |
| { |
| static const GstMetaInfo *meta_info = NULL; |
| |
| if (g_once_init_enter (&meta_info)) { |
| const GstMetaInfo *mi = gst_meta_register (MY_EXAMPLE_META_API_TYPE, |
| "MyExampleMeta", |
| sizeof (MyExampleMeta), |
| my_example_meta_init, |
| my_example_meta_free, |
| my_example_meta_transform); |
| g_once_init_leave (&meta_info, mi); |
| } |
| 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> |
| |
| </sect1> |
| |
| <sect1 id="section-allocation-bufferpool" xreflabel="GstBufferPool"> |
| <title>GstBufferPool</title> |
| <para> |
| 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. |
| </para> |
| <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> |
| |
| <sect2 id="section-allocation-pool-ex" xreflabel="GstBufferPool-ex"> |
| <title>GstBufferPool API example</title> |
| <para> |
| 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. |
| </para> |
| </sect2> |
| |
| <sect2 id="section-allocation-pool-impl" xreflabel="GstBufferPool-impl"> |
| <title>Implementing a new GstBufferPool</title> |
| <para> |
| WRITEME |
| </para> |
| </sect2> |
| |
| </sect1> |
| |
| <sect1 id="section-allocation-query" xreflabel="GST_QUERY_ALLOCATION"> |
| <title>GST_QUERY_ALLOCATION</title> |
| <para> |
| 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: |
| </para> |
| <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> |
| |
| <sect2 id="section-allocation-query-ex" xreflabel="Allocation-ex"> |
| <title>ALLOCATION query example</title> |
| <para> |
| 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>. |
| </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> |
| <para> |
| Implementors of these methods should modify the given |
| <classname>GstQuery</classname> object by updating the pool options |
| and allocation options. |
| </para> |
| </sect2> |
| </sect1> |
| </chapter> |