pwg: flesh out allocation docs
authorWim Taymans <wim.taymans@collabora.co.uk>
Tue, 2 Oct 2012 09:34:47 +0000 (11:34 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Tue, 2 Oct 2012 09:34:47 +0000 (11:34 +0200)
Add more examples.
Add example for implementing new metadata.
Add programs to the docs (again?), it seems to contain useful info.

docs/manual/appendix-programs.xml
docs/manual/manual.xml
docs/pwg/advanced-allocation.xml

index 3ef54f0..b888a17 100644 (file)
@@ -79,7 +79,7 @@ main (int argc, char *argv[])
       GError *err = NULL; /* error to show to users                 */
       gchar *dbg = NULL;  /* additional debug string for developers */
 
-      gst_message_parse_error (msg, &err, &dbg);
+      gst_message_parse_error (msg, &amp;err, &amp;dbg);
       if (err) {
         g_printerr ("ERROR: %s\n", err-&gt;message);
         g_error_free (err);
@@ -193,6 +193,7 @@ gst-inspect mad
     </para> 
 
     <screen>
+<![CDATA[
 Factory Details:
   Rank:         secondary (128)
   Long-name:            Audio Sink (OSS)
@@ -325,6 +326,7 @@ Element Properties:
   device              : OSS device (usually /dev/dspN)
                         flags: readable, writable
                         String. Default: "/dev/dsp"
+]]>
     </screen>
 
     <para> 
index 0f147b9..14f32d1 100644 (file)
@@ -50,6 +50,7 @@
 <!ENTITY COMPONENTS           SYSTEM "highlevel-components.xml">
 
 <!-- Appendices -->
+<!ENTITY PROGRAMS             SYSTEM "appendix-programs.xml">
 <!ENTITY CHECKLIST            SYSTEM "appendix-checklist.xml">
 <!ENTITY PORTING              SYSTEM "appendix-porting.xml">
 <!ENTITY INTEGRATION          SYSTEM "appendix-integration.xml">
      - table please...
     -->
 
+    &PROGRAMS;
     &CHECKLIST;
     &PORTING;
     &INTEGRATION;
index 1a93402..a50184f 100644 (file)
       and size can be changed.
     </para>
     <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>
       <classname>GstMemory</classname> objects are created by a
       <classname>GstAllocator</classname> object. To implement support
       for a new kind of memory type, you must implement a new allocator
       object.
     </para>
+    <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" xreflabel="GstAllocator">
+      <title>Implementing a GstAllocator</title>
+      <para>
+        WRITEME
+      </para>
+    </sect2>
+
   </sect1>
 
   <sect1 id="section-allocation-buffer" xreflabel="GstBuffer">
         </para>
       </listitem>
     </itemizedlist>
-    <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 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 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">
       backing up the memory of the buffer. This makes it easier for elements
       to locate the X image from the buffer.
     </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 thse 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 (meta_info == NULL) {
+    meta_info = gst_meta_register (MY_EXAMPLE_META_API_TYPE,
+        "MyExampleMeta",
+        sizeof (MyExampleMeta),
+        my_example_meta_init,
+        my_example_meta_free,
+        my_example_meta_transform);
+  }
+  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">
       to the buffers in the pool or such as enabling specific padding on
       the memory in the buffers.
     </para>
+
+    <sect2 id="section-allocation-pool-ex" xreflabel="GstBufferPool-ex">
+      <title>GstBufferPool API example</title>
+      <para>
+        WRITEME
+      </para>
+    </sect2>
+
+    <sect2 id="section-allocation-pool-new" xreflabel="GstBufferPool-new">
+      <title>Implementing a new GstBufferPool</title>
+      <para>
+        WRITEME
+      </para>
+    </sect2>
+
   </sect1>
 
   <sect1 id="section-allocation-query" xreflabel="GST_QUERY_ALLOCATION">
       from the available bufferpools, allocators and metadata how it will
       allocate buffers.
     </para>
-    <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>
+
+    <sect2 id="section-allocation-query-ex" xreflabel="Allocation-ex">
+      <title>ALLOCATION query example</title>
+      <para>
+        WRITEME
+      </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>
+    </sect2>
   </sect1>
 </chapter>