= Technical Specification =

TBD: - plugin parameter interpolation
      - zero copy for generators - host supplies buffer to be filled between process_func() calls


Weed API Version Changes
------------------------
100 - first release
110 - added WEED_PARAMETER_ELEMENT_PER_CHANNEL
120 - added WEED_YUV_CLAMPING and WEED_YUV_SUBSPACE
130 - added WEED_CHANNEL_RESIZE_ON_ROWSTRIDES_CHANGE
131 - added WEED_FILTER_PROCESS_LAST, removed WEED_COLORSPACE_HSV
132 - added threading hint, and later WEED_CHANNEL_ALPHA_PREMULT
133 - added gamma correction, package_name

200 - separated WEED_API_VERSION and WEED_FILTER_API_VERSION.

Updated WEED_API_VERSION to 200
  - added weed_leaf_flag_set(), weed_leaf_flag_get(). Filter API changes are listed below.
  - Added typedef for weed_realloc_f.

Possibly non-backwards compatible:
  - removed weed_leaf_set_caller(),
  - changed meaning of return value from weed_leaf_element_size() for WEED_SEED_VOIDPTR
  - WEED_SEED_VOIDPTR will now be cast to / from uint64_t instead of void *.
  - added WEED_VOIDPTR_SIZE, defined as sizeof(void *)
  - changed typedef for weed_size_t to be uint32_t, (replacing size_t in previous versions)
  - added typedef for weed_error_t as int32_t, (replacing int in previous versions)


Changelog:
21/04/06 salsaman.
Added notes about WEED_PLANT_UNKNOWN, clarified "max_repeats" for
filters, clarified number of elements in parameter_template
"default". Removed "TODO" from refs. to Weed EVENTS spec. Version number unchanged.

14/08/06 salsaman
Allow channels based on templates with "max_repeats" to be disabled at
any time, even if the template is not marked "optional". Version
number unchanged.

20/08/06 salsaman
Small change to description of "max_repeats". Number of channels may
only be _reduced_ after init(); and only by setting "disabled" to WEED_TRUE. Version
number unchanged.

22/08/06 salsaman
Added "new_default" leaf for parameter templates which have the
WEED_PARAMETER_VARIABLE_ELEMENTS flag set. Version number unchanged.

24/08/06 salsaman
Added "ignore" leaf for parameters for use in interpolation where the
"value" contains a list. Version number unchanged. Removed
WEED_PLANT_UNKNOWN since it is not part of the API.

24/09/06 salsaman
Corrected/clarified some parts of the text. API unchanged.

30/10/06 salsaman
Add host-only function weed_leaf_delete(). Since it is host only, API
version is unchanged.

11/12/06 salsaman
Added WEED_CHANNEL_FOLLOWS_OUTPUT and
WEED_PARAMETER_ELEMENT_PER_CHANNEL. Updated spec to 1.1 and API
version to 110.

13/12/06 salsaman
Add optional "target_fps" to filter_instance, change it from an array to a
single value. API version unchanged.

25/07/07 salsaman
Add filter flag WEED_FILTER_HINT_IS_POINT_EFFECT. API version unchanged.

27/03/08 salsaman
Corrected some typos and clarified about passing function pointers.

07/06/08 salsaman
Updated to libweed. Spec is now at version 3.0. Moved text around to split into Weed and
Weed Effects.

14/06/08 salsaman
Add YUV_clamping, YUV_subspace. Remove "h_shift" and "v_shift". Allow
generators to set channel sizes, but they should attempt to use the
host set size. Clarified some points. API version was updated to 120.

03/11/08 salsaman
Removed requirement that weed plugin file extensions be .wo, since this was discovered to be non-portable.

11/10/09 salsaman
Correct a typo, and try to further clarify about function passing.

9/11/09
Added WEED_CHANNEL_RESIZE_ON_ROWSTRIDES_CHANGE
API Version to 130

5/02/10 salsaman
Clarified text about default getter and bootstrap process.

7/02/10 salsaman
Removed WEED_COLORSPACE_HSV, deprecated WEED_FILTER_FOLLOWS_OUTPUT, 
added WEED_FILTER_PROCESS_LAST

16/04/10 salsaman
Clarified meaning of YUV_subspace

22/09/10 salsaman
Clarified YUV_subsampling, *changed value of default*.

21/10/10 salsaman
Clarified text about plugin data and icon directories.

17/03/11 salsaman
Switched WEED_FILTER_HINT_IS_POINT_EFFECT to WEED_FILTER_HINT_NO_THREADING **

6/08/11 salsaman
Corrected spelling error WEED_HINT_INT -> WEED_HINT_INTEGER

7/01/12 salsaman
Add clarifying notes about out parameters.

19/01/12 salsaman
Add channel flag WEED_CHANNEL_ALPHA_PREMULT. API unchanged.

23/01/12 salsaman
Clarified range for AFLOAT.

29/07/12 salsaman
** Corrected name of flag and description to WEED_FILTER_HINT_MAY_THREAD

15/11/12 salsaman
added clarifying remarks for number of values in parameter defaults.

01/03/13 salsaman
corrected description about static function versions

17/03/13 salsaman
added "extra_authors" leaf for plugin_info. Corrected description about static functions for plugins.
added "rowstride_alignment_hint" for channel templates.

17/09/2013 salsaman
Clarified description of "group" leaf for WEED_HINT_SWITCH parameter templates.

12/10/2013 salsaman
Add "hidden" option to filter_class gui.

30/09/2014 salsaman
Add missing type documentation for "fps".

04/03/2016 salsaman
Add optional "copyright" leaf to PLUGIN_INFO.


28/10/2019 salsaman
Version 2.0. Spec changes:
Allow plugins access to weed_plant_free().
Changed return value from weed_leaf_element_size() for WEED_SEED_VOIDPTR (now returns the data size rather than sizeof(void *)).
Added WEED_VOIDPTR_SIZE.
Added typedefs weed_error_t, weed_size_t, weed_voidptr_t.
Added typedefs weed_realloc_f, weed_calloc_f, weed_memmove_f.
weed_size_t is now int32_t rather than size_t.
Calling weed_leaf_get() for an existing leaf but with and invalid idx returns WEED_ERROR_NOSUCH_ELEMENT rather than
WEED_ERROR_NOSUCH_LEAF (BUGFIX).
Added WEED_ABI_VERSION (synonym for WEED_API_VERSION).
Added WEED_ERROR_IMMUTABLE and WEED_ERROR_UNDELETABLE.
Added WEED_FLAG_UNDELETABLE and WEED_FLAG_IMMUTABLE.


Filter API:
Added WEED_FILTER_API_VERISON, defined as 200 for this release.
Added WEED_ERROR_BADVERSION.
Added optional "flags" leaf to HOST_INFO.
Added WEED_GAMMA_UNKNOWN, WEED_GAMMA_LINEAR, WEED_GAMMA_SRGB (weed-palettes.h)
Added WEED_HOST_SUPPORTS_LINEAR_GAMMA flag bit for HOST_INFO "flags".
Added WEED_FILTER_HINT_LINEAR_GAMMA for FILTER_CLASS "flags"
Added definitions for WEED_GAMMA_UNKNOWN, WEED_GAMMA_LINEAR, WEED_GAMMA_SRGB.
Added optional "gamma_type" leaves to PARAMETER_TEMPLATE, PARAMETER, CHANNEL.
Moved typedef weed_timecode_t from weed.h
Removed WEED_LEAF_READONLY_PLUGIN, WEED_LEAF_READONLY_HOST and WEED_ERROR_LEAF_READONLY.



(C) Gabriel "Salsaman" Finch 2005 - 2020

With contributions by: Niels Elburg, Dennis "Jaromil" Rojo, Andraz
Tori, and Oyvind "Pippin" Kolas.

This document describes an open standard (Weed / libweed).
The license of this document is the GNU FDL (GNU Free Documentation License) version 1.3 or higher. 

Weed is an object system developed for video/audio processing. Weed
currently has modules for video/audio effects (weed-effects), and further modules are being
developed for handling audio and video data (weed layers) as well as timelines (weed events).





== WEED_API_VERSION / WEED_ABI_VERSION ==

These equivalent preprocessor symbols are defined as 200 for this version of the specification. This
number may be increased for future revisions of the spec.

Note:
libweed-utils provides the following function:

  int check_weed_abi_compat(int32_t higher, int32_t lower)

which returns WEED_TRUE if the two versions are compatible, WEED_FALSE otherwise.
(or if either version is higher that the library version, since it can't know the future...)



=== General overview ===

Weed can be employed at different levels depending on the needs of the programmer.

Level 0: -

a program would simply #include weed.h and may set the symbols
#HAVE_WEED_PLANT, #HAVE_WEED_LEAF and #HAVE_WEED_DATA
At this level there is no definition of these types, however the core function types (listed below) are defined.
The fundament types are defined along with some error numbers and so on.



Level 1: an application #includes weed.h and uses the built-in type definitions weed_data_t, weed_leaf_t, weed_plant_t.

The application may now use the a reference implementation of libweed for all of the core functions. An application wishing to use
libweed just needs to call weed_init(abi_level, init_flags) to get the correct version of the functions for that abi version.
In most cases it suffices to just call weed_init(WEED_ABI_VERSION, 0)
and check that the returned value is not WEED_ERROR_BADVERSION.

- weed_get_abi_version() may be called first to get the ABI level the library was compiled with.


Level 2:

at this level there is a distinction between plugins and hosts.
The host program is normally the one which will dlopen() or link with the plugins, pass data to them for processing, etc.

Hosts should #include weed-host.h before weed.h, and plugins should instead #include weed-plugin.h

The principle difference at this level is that the plugin links staticly scoped versions of the core functions,
whereas the host links global ones.

Plugins also relinquish access to the weed_leaf_set_flags(),
weed_leaf_set_private_data(), and weed_leaf_get_private_data() functions.



Level 3:

at his level host and plugin may choose to use a utilities library such as weed-utils.
Only hosts should link with this library. Plugins simply need to include the weed-utils.h header.
The reference implementations provide typed getters and setters for single and array values.



Level 4:

host and pugins would be tailored to a particular role (multiple roles may be selected provided their symbols
do not conflict.)

For example for video and audio plugins, host and plugins would #include weed-effects.h

Depending on the application type there may be other optional or mandatory headers.
In the video effects example, Weed offers the optional headers weed-palettes.h and weed-compat.h

There also a C / C++ code library which effects plugins may use, weed-plugin-utils.c. This is designed to complement
weed-utils.h, but it does not rely on it. This provides convenient versions of most of the functions that a plugin will need to use
to interface with the Weed Effects system.

For hosts there is libweed-host-utils (under development / testing) which provides many convenience functions for the host
to interface with the Weed Effects system.





== WEED PLANTS ==

A ''plant'' in Weed is a collection of one or more ''leaves''.

Each plant has one MANDATORY leaf, with the key WEED_LEAF_TYPE (defined as "" in weed.h).
Depending upon the value of this leaf, the plant may have other mandatory and optional leaves defined by an 
application specification.

"type" is a single valued leaf with seed_type WEED_SEED_INT (See below: seed_types).

The "type" is passed as a parameter in the weed_plant_new() function.
This function returns a pointer to newly allocated plant with the "type" leaf value set
to the plant_type.


Plant types 1 - 64 are reserved for the Weed Effects system.
Plant types 128 - 255 are reserved for the Weed Layers system (in development)
Plant types  256 - 511 are reserved for the Weed Events system (see Weed Event spec.)

Plant types >= 16384 are free for custom use.






== LEAVES ==

As mentioned above, each "plant" is simply a set of one or more "leaves".

Each leaf has at least:
 * a ''key'' a unique (for the plant) non-NULL ASCII string; cannot be changed once the leaf is created.

 * a ''value'' (an array of 0 or more elements, the type depends on the seed_type of the leaf)

 * ''number of elements'' (weed_size_t) contained in the value field.

 * a ''seed_type'' (uint32_t). Defines the type of the value field. Cannot be altered after the leaf is created.

 * a bitmap ''flags'' field (uint32_t)

ABI 200+:

 * a void * "private_data"



== SEED TYPES ==

The "seed type" denotes the type of the value field in a leaf.
Weed provides the following 'fundamental' types:

 * WEED_SEED_INT     [1] : equivalent to a signed /unsigned 32 bit integer. size = 4 bytes

 * WEED_SEED_DOUBLE  [2] : equivalent to a 64 bit signed double. size = 8 bytes

 * WEED_SEED_BOOLEAN [3] : signed /unsigned 32 bit integer, acceptable values are WEED_FALSE or WEED_TRUE. size = 4 bytes 

 * WEED_SEED_STRING  [4] : 0 terminated array of char (max length is uint32_max). (char *)NULL is treated as a zero length string.
   		     	   size = strlen(value). Unless otherwise note, the character set is utf-8.

 * WEED_SEED_INT64   [5] : signed /unsigned 64 bit integer . size = 8 bytes




 * WEED_SEED_FUNCPTR    [64]  : corresponds to a function pointer. In the case of getting / setting values, the address of a variable
                                or an array holding the function pointer should be used.
				Size == WEED_FUNCPTR_SIZE

'''Pointer''' types (number > 64) Size = WEED_VOIDPTR_SIZE.

 * WEED_SEED_VOIDPTR    [65]  : corresponds to a C void * type. (size is dependent on the operating system)


 * WEED_SEED_PLANTPTR   [66]  : a pointer to another weed plant.
   			   

WEED_SEED_FIRST_CUSTOM	[1024]
Types >= 1024 are reserved for custom use. Custom seeds MUST be pointer types.
(A future version of the API may allow for non pointer custom types)



== WEED CORE FUNCTIONS ==

 * weed_plant_t *weed_plant_new (int32_t plant_type) : allocates and returns a new Weed plant
   with a single leaf, "type" with a single element of type WEED_SEED_INT, whose value defines
   the type of the plant.
   In case of memory error, the plant will not be created and NULL shall be returned.





 * weed_error_t weed_leaf_set (weed_plant_t *plant, const char *key, uint32_t seed_type, weed_size_t num_elems, void *values)

    Set leaf values and number of elements.

    If plant is NULL, the function shall return WEED_ERROR_NOSUCH_LEAF.
    If key is NULL or zero length, it is equivalent to setting the "type" leaf.

    IF seed_type is not a pointer / funcptr type (>= 64) and not one of the fundamental types,
    then WEED_ERROR_WRONG_SEED_TYPE is returned and the leaf is not created or altered.

    If the leaf already exists and has a different seed_type then WEED_ERROR_WRONG_SEED_TYPE will be returned and the value
    will not be updated.
    
    values should be an array of the appropriate type and size, cast to a void *

    for WEED_SEED_INT, values should be (void *)(int32_t[num_elems]) or (void *)(uint32_t[num_elems])
    for WEED_SEED_DOUBLE, values should be (void *)(double[num_elems])
    for WEED_SEED_BOOLEAN, values should be (void *)(int32_t[num_elems])
    for WEED_SEED_INT64, values should be (void *)(int64_t[num_elems]) or (void *)(uint32_t[num_elems])
    for WEED_SEED_STRING, it should be (void *)(char *[num_elems]),
    for WEED_SEED_FUNCPTR, (void *)(weed_funcptr_t[num_elems])
    for WEED_SEED_VOIDPTR, (void *)(weed_voidptr_t[num_elems])
    for WEED_SEED_PLANTPTR, (void *)(((weed_voidptr_t)(weed_plant_t *))[num_elems])
    custom types (seed_type >= 1024) would be similar to WEED_SEED_PLANTPTR, but with a different seed_type.

    The values array is assumed to be of the correct size and type.

    If the leaf does not exist in the plant, then it will be created and added to the plant, otherwise the value and array size
    of the existing leaf will be amended and the old data will be freed.


    If num_elems is 0 then only the seed_type is set (or checked if the leaf already exists),
    and while in this state any attempts to retrieve the value with weed_leaf_get() shall return WEED_LEAF_NOSUCH_ELEMENT.
    This is useful if you want to fix the seed_type of a leaf without setting any particular value.

    Passing a NULL pointer for values and num_elems > 0 will likely lead to undesired behaviour.

    In case of a memory error, WEED_ERROR_MEMORY_ALLOCATION is returned, and either the leaf is not created,
    or if it already exists then its num_elems is set to zero and its value to NULL.


    (as of API 200) If the WEED_FLAG_IMMUTABLE flag bit is set for the leaf, then WEED_ERROR_IMMUTABLE
    is returned and the leaf is not altered.

    Note:
    Attempting to set the number of elements of the "type" leaf to a value other than 1 will result in WEED_ERROR_NOSUCH_ELEMENT
    being returned and the value will not be altered.





* weed_error_t weed_leaf_get (weed_plant_t *plant, const char *key, int32_t idx, void *value) :

    returns the nth (starting from 0) element of the specified leaf.

    value should be typecast to a (void *) from a pointer of the appropriate type, depending on the seed_type of the leaf.
    (If the seed_type is not known, it should be retrieved first with weed_leaf_get_seed_type()).

    For WEED_SEED_INT it should be (void *)(int32_t *) or (void *)(uint32_t *).
    For WEED_SEED_DOUBLE it should be (void *)(double *)
    For WEED_SEED_BOOLEAN it should be (void *)(int32_t *)
    For WEED_SEED_INT64 it should be (void *)(int64_t *)
    For WEED_SEED_STRING, a (void *)(char **),
    for WEED_SEED_FUNCPTR, (void *)(weed_funcptr_t *),
    for WEED_SEED_VOIDPTR (void *)(weed_voidptr_t *),
    for WEED_SEED_PLANTPTR (void *)(*((weed_voidptr_t)(weed_plant_t *)))

    custom types (>= 1024) would be similar to WEED_SEED_PLANTPTR but with a different seed_type.

    If if the leaf does not exist, or plant is NULL, WEED_ERROR_NOSUCH_LEAF is returned.
    If key is NULL or zero length, it is equivalent to getting the "type" leaf.

    If the leaf exists but the element does not exist, then WEED_ERROR_NOSUCH_ELEMENT is returned.
    Note: prior to API version 200, this would erroneously return WEED_ERROR_NOSUCH_LEAF. In the unlikely case that this behaviour
    is still required (e.g. for backwards compatibility), then set the api version < 200 in weed_init().

    the value of the leaf element will be copied to value (IF value is non-NULL) using standard memcpy(),
    and WEED_SUCCESS will be returned.

    Note:
    For WEED_SEED_STRING, it may be necessary to first call weed_leaf_element size()
    and allocate a char array of at least the returned value + 1 (to hold the terminating NUL) in which to receive the value.

    
    Note:
    It is not a programming error to pass in a NULL pointer for value. In this case, Weed will not attemt to copy to value, but will
    still return an error code: either WEED_SUCCESS, WEED_ERROR_NOSUCH_LEAF or WEED_ERROR_NOSUCH_ELEMENT.

    thus by calling:      weed_leaf_get(plant, key, 0, NULL),
    it is possible to check whether a leaf exists, and whether it has a value set.
    - if the leaf doesn't exist, then WEED_ERROR_NOSUCH_LEAF will be returned.
    - if the value of the leaf is NULL, then number of elements should be 0, and WEED_ERROR_NOSUCH_ELEMENT will be returned
    - if the value of the leaf has 1 or more elements, then WEED_SUCCESS will be returned.

   If you just want to check whether a leaf exists or not, it may be simpler to call weed_leaf_seed_type() and test if it
   returns WEED_SEED_INVALID. If you just want to check if it exists and has a value, you can call
   weed_leaf_num_elements() and test if the returned value is > 0.




* weed_error_t weed_leaf_delete (weed_plant_t *plant, const char *key)
   remove the specified leaf from the plant, and free it

   [prior to API 200, this function was not avaiable to plugins]

   if the plant is NULL or the leaf does not exist, WEED_ERROR_NOSUCH_LEAF is returned.
   If key is NULL or zero length, it is considered equivalent to trying to delete the "type" leaf.

   if the WEED_FLAG_UNDELETABLE flag bit is set then WEED_ERROR_UNDELETABLE is returned, and the leaf is not deleted.

   For leaves with seed type WEED_SEED_STRING, the data is freed for each non NULL element.

   The "type" leaf of a plant may only ever be deleted via weed_plant_free(). If you attempt to delete it with weed_leaf_delete()
   then either WEED_ERROR_UNDELETABLE will be returned (if the WEED_FLAG_UNDELETABLE bit is set for it),
   otherwise WEED_ERROR_NOSUCH_LEAF will be returned.
   (Note the normal order of precedence of errors is here reversed: WEED_ERROR_NOSUCH_LEAF would normally
   be returned BEFORE WEED_ERROR_UNDELETABLE).

   The flag bit WEED_FLAG_IMMUTABLE is ignored in this function.




* weed_size_t weed_leaf_num_elements (weed_plant_t *plant, const char *key)
   - returns the number of elements for the specified leaf.

   if the leaf does not exist or the plant is NULL, returns 0. Since it is possible to create leaves with 0 elements,
   this is not a good method to use to check whether a leaf exists or not. If you want to do this you should use
   weed_leaf_get_seed_type (as described below), or weed_leaf_get() with value set to NULL as described above.

   If key is NULL or zero length, it is considered equivalent to the "type" leaf.




 * weed_size_t weed_leaf_element_size (weed_plant_t *plant, const char *key, int32_t idx)

   If the plant is NULL, the leaf does not exist, or idx is out of range, (weed_size_t)0 will be returned.

   If key is NULL or zero length, it is considered equivalent to the "type" leaf.

   For WEED_SEED_STRING, returns the string length in bytes (without any terminating NUL); equivalent to strlen().

   if the seed_type is WEED_SEED_VOIDPTR or WEED_SEED_FUNCPTR and the value is NULL, weed_size_t(0) is returned.
   otherwise it will return WEED_VOIDPTR_SIZE or WEED_FUNCPTR_SIZE respectively.

   For all other seed types, returns sizeof(seed_type), (e.g. for WEED_SEED_INT, returns 4, for WEED_SEED_INt64, returns 8).
   




 * int32_t weed_leaf_seed_type(weed_plant_t *plant, const char *key) : get the seed_type for a leaf

   Returns the seed_type for a leaf. If the plant is NULL or the leaf does not exist, will return WEED_SEED_INVALID.
   If key is NULL or zero length, it is considered equivalent to the "type" leaf.

   This fact can be used to check whether a leaf exists or not (provided plant is non-NULL). If you want to differentiate
   between leaves that have values or not, you should call weed_leaf_num_elements() and test if the returned value is > 0,
   or use the weed_leaf_get() method described above.





 * int32_t weed_leaf_get_flags(weed_plant_t *plant, const char *key) : get the flags for a leaf

   If plant is NULL or the leaf does not exist, (int32_t)0 will be returned.

   Otherwise the value of the leaf flags is returned.

   If key is NULL or zero length, it is considered equivalent to the "type" leaf.





 * weed_error_t weed_plant_free (weed_plant_t *plant) :

   returns error WEED_ERROR_UNDELETABLE if the "type" flag has WEED_LEAF_UNDELETABLE set, and nothing will be freed.

   If the plant is NULL the function simply returns WEED_SUCCESS.

   otherwise, any leaves which do NOT have the WEED_FLAG_UNDELETABLE bit set will be freed in a similar fashion to weed_leaf_delete()

   if all of the leaves except the "type" leaf were deleted, and the "type" leaf does not have the WEED_FLAG_UNDELETABLE bit set,
   the "type" leaf will be deleted and the plant is therefore freed.
   Im this case WEED_SUCCESS is returned.
   
   If leaves other than the type leaf remain (because they were undeletable), the "type" leaf is not freed, and
   WEED_ERROR_UNDELETABLE is returned. In this case it may be necesssary to clear the WEED_FLAG_UNDELETABLE
   flag bit from the remaining leaves (e.g with weed_plant_list_leaves() and weed_leaf_set_flags()),
   before calling weed_plant_free() a second time.

   To recap:

   If the "type" leaf has the WEED_FLAG_UNDELETABLE bit set, no leaves will be deleted, and WEED_ERROR_UNDELETABLE is returned.

   Otherwise, if any of the other leaves have the flag bit set, neither they nor the "type" leaf will be deleted and
   WEED_ERROR_UNDELETABLE is returned. Leaves without the flag bit set WILL be deleted.

   if none of the leaves have the WEED_FLAG_UNDELETABLE flag bit set, all the leaves will be deleted and WEED_SUCCESS returned.

   Note that as with weed_leaf_delete(), the flag bit WEED_FLAG_IMMUTABLE is ignored in this function.



 * char **weed_plant_list_leaves (weed_plant_t *plant, weed_size_t *nleaves)
   returns a (char *)[] array of leaf keys, with the final element set to NULL. If nleaves is not NULL, its value is set to
   the number of leaves (i.e number of strings returned EXCLUDING the final NULL element).

   In case of memory error, NULL is returned, nleaves (if non NULL) is set to zero and the array is not created.

   The caller should free any non-NULL elements + the array itself when no longer required.

   If plant is NULL, the function returns a char ** array of size one, with the single element set to NULL,
   and nleaves will be set to zero.

   The standard malloc(), and memcpy() functions will be used when creating the array and all the strings.




A Weed host has access to additional functions which are not defined for or intended to be passed to plugins:

 * weed_error_t weed_leaf_set_flags(weed_plant_t *plant, const char *key, int32_t flags)

   If key is NULL or zero length, it is considered equivalent to the "type" leaf.

   Caution ! Clearing the WEED_FLAG_IMMUTABLE bit for the "type" leaf allows the plant type to be changed !

   Setting the WEED_FLAG_UNDELETABLE bit for the "type" leaf prevents ANY leaves from being freed
   using weed_plant_free().

   Setting the WEED_FLAG_UNDELETABLE bit for any other leaf prevents the "type" leaf and that leaf from being freed
   using weed_plant_free().

   Setting the WEED_FLAG_UNDELETABLE bit for any leaf also prevents that leaf from being deleted
   using weed_leaf_delete().

   The function will return WEED_ERROR_NOSUCH_LEAF if plant is NULL or leaf does not exist.


 * weed_error_t weed_leaf_set_private_data(weed_plant_t *plant, const char *key, void *data);

   		 set "private data" for a leaf. Host only function. The value of data will be copied.
		 Will return WEED_ERROR_NOSUCH_LEAF if the plant is NULL or leaf does not exist, otherwise WEED_SUCCESS.
		 Can be set even if WEED_FLAG_IMMUTABLE bit is set.


 * weed_error_t weed_leaf_get_private_data(weed_plant_t *plant, const char *key, void **data);

   		 get "private data" from a leaf. Host only function. data should be a pointer to void * in which to receive the value.
		 Will return WEED_ERROR_NOSUCH_LEAF if the plant is NULL or leaf does not exist, otherwise WEED_SUCCESS.
		 The default value is NULL if not set.


** Note that the threadsafe version of libweed requires exclusive use of the private data,
and trying to set it with that version of the library will return an error.


== LEAF FLAGS ==

Two special flag bits are defined in weed.h:

WEED_FLAG_UNDELETABLE [1 << 0] :: the leaf cannot be deleted, weed_leaf_delete will return WEED_ERROR_UNDELETABLE if you try it

and

WEED_FLAG_IMMUTABLE [1 << 1] :: the leaf value cannot be changed (but it may be deleted),
                                   weed_leaf_set returns WEED_ERROR_IMMUTABLE if you try to do so


When creating a new plant, libweed automatically will set the WEED_LEAF_IMMUTABLE flag for the "type" leaf.
Thus if you want to change the plant type, you must first clear the WEED_LEAF_IMMUTABLE flag bit, e.g.

int32_t flags = weed_leaf_get_flags(plant, WEED_LEAF_TYPE);
weed_error_t error = weed_leaf_set_flags(plant, WEED_LEAF_TYPE, flags & ~WEED_FLAG_IMMUTABLE);
if (error == WEED_SUCCESS) {
...
// now you can change the "type" of the plant

}

/// don't forget to set it back after !
error = weed_leaf_set_flags(plant, WEED_LEAF_TYPE, flags | WEED_FLAG_IMMUTABLE);



If the "type" leaf is set undeletable, then no leaves will be freed using weed_plant_free(),
the function will return WEED_ERROR_UNDELETABLE. In this case you need to clear the flag bit prior to calling weed_plant_free().

The combination of immutable and undeletable flag bits is designed so that Weed hosts can prevent plugins from
changing readonly values or freeing plants which are still referenced by the host.


Flag bits 0 - 15 are reserved for use by the Weed library. The remaining flag bits (16 - 31) may be freely used by applications.




== WEED CORE ERRORS ==
Defined in weed.h

Errors are listed here in order of precedence from highest to lowest.

 *  WEED_SUCCESS[[BR]]
    returned if no errors occured.

 *  WEED_ERROR_NOSUCH_LEAF[[BR]]
    leaf does not exist for the specified plant; returned from
    weed_leaf_get(), weed_leaf_delete(), weed_leaf_set_flags().

 *  WEED_ERROR_NOSUCH_ELEMENT[[BR]]
    plugin/host tried to read value of an invalid element number in a leaf; returned from weed_leaf_get()

 *  WEED_ERROR_WRONG_SEED_TYPE[[BR]]
    returned from weed_leaf_set() if the leaf has the WEED_FLAG_IMMUTABLE bit set

 *  WEED_ERROR_IMMUTABLE[[BR]]
    returned from weed_leaf_set() if you try to alter the value of a leaf which has the WEED_FLAG_IMMUTABLE bit set

 *  WEED_ERROR_UNDELETABLE[[BR]]
    returned if you try to delete a leaf which has the WEED_FLAG_UNDELETABLE bit set, or if weed_plant_free() finds any leaves
    with this flag bit set

 *  WEED_ERROR_MEMORY_ALLOCATION[[BR]]
    memory allocation has failed

 *  WEED_ERROR_CONCURRENCY
    libweed will return this if it detects multiple threads attempting to either set the value of a leaf simultaneously
    or delete a leaf simultaneously (see: thread concurremcy)

 *   WEED_ERROR_BADVERSION
    returned from weed_init() if the host specifies an api version that the library cannot support.


* WEED_ERROR_FIRST_CUSTOM		1024
Indicates that error numbers >= 1024 are reserved for custom errors.








---- Weed reference build  -----

The reference build consists of two parts, a header (weed.h) and a library. Use of the library is optional, but requires
inclusion of the header.



--- weed.h ---

Typedefs:


The header provides typedefs for all the core functions.
e.g. weed_leaf_get_f, weed_malloc_f.

weed_funcptr_t is tpypedef as void (*weed_funcptr_t)()
weed_voidptr_t is typedefed as (void *)
weed_size_t is typedefed as (uint32_t)      [NOT uint64_t, even on 64 bit systems !!!!]
weed_error_t is typedefed as (int32_t)
weed_plantptr_t is typedefed as (weed_plant_t *)


== Plant types ==

For convenience, weed.h defines the following plant types:

WEED_PLANT_UNKNOWN, with value 0.
WEED_PLANT_GENERIC, with value 16383
WEED_PLANT_FIRST_CUSTOM, with value 16384

Plant types >= 16384 are available for custom plant types..


==== Other symbols ====

WEED_TRUE is #defined as 1 in the header.

WEED_FALSE is #defined as 0 in the header.

WEED_ABI_VERSION is #defined as 200 in the header.

WEED_API_VERSION is a synonym for WEED_ABI_VERSION

WEED_ABI_CHECK_VERSION(version) returns WEED_TRUE if version <= WEED_ABI_VERSION, otherwise WEED_FALSE

WEED_API_CHECK_VERSION(version) is a synonym for WEED_ABI_CHECKVERSION(version)

WEED_VOIDPTR_SIZE is #defined as (sizeof(void *))

WEED_FUNCPTR_SIZE is #defined as (sizeof(weed_funcptr_t))



== Leaf keys ==
weed.h defines the following leaf keys:


WEED_LEAF_TYPE "type"  : Mandatory leaf for all plants

WEED_LEAF_WEED_API_VERSION  : "weed_api_version"
WEED_LEAF_WEED_ABI_VERSION  : WEED_LEAF_API_VERSION

Provided for convenience for use by any plant type








== Weed library functions  ==

There now follows a description of the Weed reference library (libweed).

Currently this library is offered in two versions,
one using the standard memory functions, and a second using glib's slice allocator for slighlty
higher performance (libweed-gslice).
In addition a threadsafe version of either may be compiled.
Currently this adds a dependency on libpthread, but is highly recommended when using the library
with multiple threads.

The reference is written with performance in mind, for example a hash function is used to locate
leaf keys.

Rough benchmarking with plants of up to one million randomly created leaves
has not shown any considerable performance issues.

The libray and header are relatively compact - the stripped libweed.so is around 20Kb in size
on an average linux system and the weed.h header contains roughly 250 lines
(including whitespace, comments and preamble).




== GETTING/SETTING LEAF VALUES ==

For WEED_SEED_STRING, libweed will allocate a new string when getting / setting the value. For all other seed_types,
copy is by reference.



== COMPILING WITH WEED ==

In order to use the reference build of Weed, a program should #include

weed/weed.h


and optionally link with libweed (libweed-gslice).


Some uses of Weed (e.g for effects plugins or events may require further headers, see below for an example).



== weed_get_abi_version() ==

   int32_t weed_get_abi_version(void)

Prior to calling weed_init(), weed_get_abi_version will return the Weed ABI version used to compile libweed.
When calling weed_init(), the ABI version selected should be no higher than this, else WEED_ERROR_BADVERSION will be returned.
If the minimum version which the host supports is higher than this, then the implementation of libweed in question may not be used.

After a succesful call to weed_init(), this function returns the ABI version which was specified in that function.


== weed_init() ==

   Prior to calling any other Weed functions in the reference libweed, a program (host, but not a plugin) must call:

 * weed_error_t weed_init(int32_t api_version, uint64_t flags)

     The application passes in the ABI version it wants to use. The function will set function
     pointers to the correct ABI versions of the core functions. Usually the program would use WEED_ABI_VERSION defined in
     weed.h. All ABI versions >= 200 are guaranteed to be supported in every future version of the library.

     If the host selects an ABI version < 100 or > the highest version the library supports, WEED_ERROR_BADVERSION will
     be returned, otherwise WEED_SUCCESS is returned.

     A call to weed_get_abi_version() prior to calling weed_init() will return the highest ABI version the library supports, as
     detailed above.

Flags:
	as of Weed ABI version 200, the current flag bits are defined for the flags passed to weed_init().

	WEED_INIT_FLAG_STD_STRINGFUNCS		(1<<0) ::
	may be set during development to avoid spurious error warnings in valgrind etc.
	may have a minor detrimental affect on performanc

	WEED_INIT_FLAG_ALLBUGFIXES			(1<<1)
	set this flagbit to enable potential backported bugfixes which may theoretically impact existing behaviour, as explained below


 == BUGFIXES ==

     Bugfixes for defects discovered in libweed will be backwards ported to prior ABI versions,
     provided they do not adversly affect the behaviour of existing applications

     If an error is discovered in the spec, the documentation will be corrected, and if necessary, the code amended to reflect this.

     If a code amendment is likely to affect the behaviour of existing programs in an adverse way - for example if programs
     rely on the old buggy implementation to function correctly, then the ABI version will be increased and the bugfix applied in the
     new ABI version. Such amendments will only be applied in prior ABI versions if WEED_INIT_FLAGS_ALLBUGFIXES is set
     in the flags when calling weed_init().
     Use of this flagbit allows a host to use the bugfixed version without updating the ABI version and thus continue using existing plugins.
     There is a chance that this  may cause problems with older plugins in cases where they rely on the buggy implementation to function
     correctly. The ideal is thus for both host and plugins to upgrade, but in practice this may not be possible.



== Pre-processor symbols ==
The Weed header checks for the following pre-processor symbols:

==== HAVE_WEED_PLANT_T ====

The reference implementation provides default
implementations of a Weed plant. This can be overriden at compile time using:
{{{
#define HAVE_WEED_PLANT_T
}}}
before
{{{
#include <weed/weed.h>
}}}

This need only be done in the host.
In this way a host can provide its own defintion of a Weed plant, and
provide its own implementation of the core functions, whilst still making
use of the rest of the header file.

Similarly, HAVE_WEED_LEAF_T and HAVE_WEED_DATA_T allow for finer levels of overloading.





=== Compiling a program with Weed: ====

If the program wishes to use Weed, it should include weed/weed.h


=== Compiling a program with libweed ====

If a program wishes to use a reference build of libweed, it should include weed/weed.h and link against libweed


It may optionally include weed/weed-utils.h and link against libweed-utils.


=== Compiling a Host with Weed: ====

If the program wishes to use act as a Weed host, it should include weed/weed-host.h  and weed/weed.h in that order.

It may optionally include weed/weed-utils.h and link against libweed-utils.


=== Compiling a Plugin with Weed: ====

If the program wishes to use act as a Weed plugin, it should include weed/weed-plugin.h  and weed/weed.h in that order.


An example of Compiling plugins and hosts for different applications (in this case, video filters) is given below.




========== Library Implementation details  ====================

The library uses a hash function for comparing keys, and then a strcmp on only on a match.
Thus searching the list is usually quite rapid.

The "type" leaf (i.e the plant) is always the first leaf. Newly added leaves are appended directly after this.
Thus, when adding multiple leaves, more frequently accessed ones should be added last.

---- Platform availability  ---
Th library and plugins have been tested on Linux, and on Windows 10 using msys2 / mingw.
Patches for other operating systems are welcome.

The headers and libraries are usable with standard C and C++.

The only system headers required are: stddef.h, inttypes.h, string.h, amd stdlo,h,
For the gslice implementation, glib.h libglib is also required.


SDK:

and SDK is in development. The full release will consist of:

For plugin writers:

This spec.
The Weed Audio spec.

weed-plugin.h
weed.h
weed-utils.h
weed-effects.h
weed-plugin-utils.h
weed-plugin-utils.c
weed-palettes.h
weed-compat.h

a template plugin
a set of reference plugins.


For host writers:

This spec.
The Weed Audio spec.
The Weed Events spec.
The Weed Layers spec. (under consideration).

weed-host.h
weed.h
weed-utils.h
weed-effects.h
weed-palettes.h
weed-compat.h
weed-events.h  (under consideration). [timeline handling integrated in the Weed system]

libweed (3 versions: standard memory functions, gslice allocator, pthread mutex).

libweed-utils

libweed-host-utils and weed-host-utils.h  (under final development / testing).
libweed-layers (under consideration) [used for manipulating channel data sent to and received from a plugin]



Example host functions:

e.g.

- loading and setting up a plugin
- retrieving the filter classes from a plugin
- sanity checking a filter
- creating an instance from a filter
- setting in parameters
- calling the init_func
- calling process_func
- calling deinit_func
- threading
- unloading the plugin
- creating a user interface for the filter


=== thread concurrency ====

For portabilty, the standerd library does not implement any kind of mutex locking.

** a fully threadsafe version is currently in test phase and thus far is working very well (see below).
This does, however require linking the library with libpthread.

The following applies to the NON-threadsafe version
In general the following rules should be observed:
- two threads attempting to set a leaf value at the same time SHOULD be reasonably safe, the only risk is
  if one thread updates the leaf's num_elements between the other thread reading it and writing it - in this case num_elements
  could mismatch the number of actual  elements in data
  (if libweed is compiled with gcc then atomic gets / sets are used if suppported, so it is almost guaranteed to  be safe)

  The majority of the time libweed sgould be able to detect this, and it will return WEED_ERROR_CONCURRENCY
  to one thread, and its value will be ignored.

- if two threads attempt to add new leaves simultaneously to the same plant, there is a miniscule chance that only one will be added.
 (if libweed is compiled with gcc then atomic gets / sets are used if suppported, so it is almost guaranteed to  be safe)

 The majority of the time libweed should be able to  detect this, and  it will return WEED_ERROR_CONCURRENCY
  to one thread, and its leaf will nor be added.

- attempting to read a leaf's value whilst it is being set is OK;
   however weed_leaf_set() will return WEED_ERROR_NOSUCH_ELEMENT for an existing leaf, until the value is fully updated.

- getting the seed type is fine as this is constant

- getting / setting flags is fine

- reading the number of elements may temporarily return 0 whilst the value is being updated


- two threads attempting to delete a leaf at the same time should be reasonably safe;
  the only risk is if one thread updates the previous node's next pointer between the other thread reading it and writing it.
  (if libweed is compiled with gcc then atomic gets / sets are used if suppported, so it is almost guaranteed to  be safe.)

The majority of the time libweed will be able to detect this, and it will return WEED_ERROR_CONCURRENCY
  to one thread, and its value will be ignored.


calling weed_leaf_delete() or weed_plant_free() simultaneously with any other function affecting the plant is still very bad idea.
Don't do it !!


To avoid potential problems, it is recommended NOT to update a leaf whilst there is the possiblity that another thread is
reading it.





== THREADSAFE VERSION ==
A fully threadsafe version of libweed is now available.
This version requires compilation with libpthread. It utilizes the leaf "private data" to point to an allocted pthread rwlock.

The implementation details are as follows:

- any read operations first obtain a read lock on the plant
(when referring to 'plant' here, it should be understood to mean the mandatory "type" leaf; 'leaf' in this context means
any of the other leaves)

- once a leaf is located, either a read or write lock on the leaf is obtained and the plant read lock is subsequently released

- reading a leaf value, number of elements, seed_type or flags requires a read lock on the leaf

- when updating a leaf value, a write lock on the plant is first obtained, If the leaf is located then a write lock on the leaf is obtained
  and the plant lock released. If the leaf does not exist, the plant write lock is maintained until the new leaf has been added.

- listing the plant leaves requires a plant read lock

- adding a new leaf requires a write lock on the plant

- deleting a leaf requires both a write lock on the plant, and write lock on the leaf. Once both are obtained, the leaf write lock
  is relinquished and the leaf deleted.

- freeing a plant requires a write lock on the plant, and then a write lock on each leaf.

- getting or setting the private_data of a leaf will return an error (WEED_ERROR_CONCURRENCY). This can be used to test for the
  presence of the thread safety feature: e.g:

  int threadsafe = 0;
  weed_plant_t *test = weed_plant_new(0);
  if (weed_leaf_get_private_data(test, WEED_LEAF_TYPE) == WEED_ERROR_CONCURRENCY) threadsafe = 1;
  weed_plant_free(test);



--- deadlocks ---
There is no possibility of a dealock in this system. Consider:
- a thread holding a read lock can only lock out another thread which wants a write lock
- a thread holding a write lock can lock out threads wanting read or write locks

There are only a limited number of circumstances in which write locks are required:
1 - adding a new leaf (plant write lock) - the thread holding this lock may update the plant structure, however this will not
     affect the individual leaves. No firther locks are required, therefore it cannot dealock.

2 - updating a leaf (plant read lock -> leaf write lock) :: theoretically a dealock could occur if a thread holding a write lock on
      a leaf required a write lock on the plant. However, since the order is always plant lock -> leaf lock, this cannot occur.


3 - deleting a leaf (plant write lock leaf write lock). Similar to 2) any thread holding a leaf write lock will already have a plant write lock
    or will unlock the leaf after updating it.


4 - freeing a plant (plant write lock leaf write locks). Again. any leaf holding a leaf write lock will already have a plant write lock, or not
     need one.

In other words there are no situations where a thread holding a lock which blocks another thread can itself
be blocked by the second thread needing one of the first threads locks.
Either the second thread would already have obtained that lock and the first thread would have been locked out,
or else it will perform its read /write operation and then unlock all if its locks, thus allowing the first thread to proceed.






== WEED EFFECTS EXAMPLE ==

There now follows an example of using Weed for a specific role, in this case, video effects.

There is also a Weed Audio Extension, and a Weed Events Extension, which are documented separately.
Other roles and extensions may be added in the future.



== compiling a host for Weed Effects ===

The host should include weed/weed-effects.h after weed/weed-host.h and weed/weed.h

If using video effects it may optionally include  weed/weed-palettes.h




== COMPILING A PLUGIN WITH WEED ==

An effects plugin wishing to use the reference build of Weed should #include the following headers:

weed/weed-plugin.h // BEFORE weed.h
weed/weed.h
weed/weed-effects.h // AFTER weed.h

and for a video effect:
weed/weed-palettes.h // before or after any other headers

If plugins wish to use weed-utils then they should #include weed/weed-utils AFTER weed-plugin.h.

Plugins should NOT be linked directly with libweed or libweed-utils, as they would be using the host version of the core
functions. weed-utils.h contains a small amount of C code, which replicates some of the functions of libweed-utils for plugins.
The inclusion of this header is optional, but it provides typecast getters and setters for for single values and arrays.

TODO: allow disabling of the code inclusion.


Plugins may optionally include weed/weed-plugin-utils.h and weed/weed-plugin-utils.c
The reason for including the code is due to the fact that if the pl;ugins dynamically linke with libweed-plugin-utils then they would
be running the host versions of the core functions. In addition, dynamic libraries (i.e. plugins) cannot easily be linked with static
libraries.

weed-plugin-utils.c is crafted in such a way that it does not require any Weed headers or libriaries other than weed-plugin-utils.h

In addition, #defines are used to enable / disbale specific groups of functions, so that the plugins are not bloated with unnecesary
code. The typical size of a stripped plugin on compiled with gcc on Linux is 10 -30 kilobytes.


== WEED-COMPAT.H ==
weed/weed-compat.h is an optional include, provided for compatibility with some external libraries.
It will automatically include weed/weed-palettes.h if necessary

It will #define WEED_COMPAT_VERSION

If you #define NEED_FOURCC_COMPAT before calling it, then it will provides the following function:

int fourccp_to_weedp(unsigned int fourcc, int bpp, int *interlaced, int *sampling, int *sspace, int *clamping)
which will attempt to return a weed palette from an input fourcc code and bpp
- bpp is the pixel size in bits, currentl only 24 and 32 are recognised (e.g 24 for RGB, 32 for RGBA)

interlaced will be set to 1 if the palette is interlaced, otherwise 0
sampling will return the YUV sampling (or WEED_YUV_SAMPLING_DEFAULT if it could not be ascertained)
sspace will return the YUV subspace e.g. WEED_YUV_SUBSPACE_YCBCR, WEED_YUV_SUBSPACE_BT709
clamping will return the YUV clamping type, WEED_YUV_CLAMPING_CLAMPED or WEED_YUV_CLAMPING_UNCLAMPED

as of WEED_COMPAT_VERSION 0.11.0 it will also #define WEED_FOURCC_COMPAT in this case.

for the Weed Audio extension:

as of WEED_COMPAT_VERSION 0.12.0, if USE_AVUTIL_CHANNEL_LAYOUTS is defined before including the header,
and libavutils/channel_layouts.h is available, then it will be possible to use libavutil audio channel names and layouts natively
in Weed.
For example:
WEED_CH_FRONT_LEFT will be defined as AV_CH_FRONT_LEFT
and
WEED_CH_LAYOUT_STEREO will equal AV_CH_LAYOUT_STEREO

etc.

in this case WEED_AVUTIL_CHANNEL_LAYOUTS will be defined, and WEED_CHANNEL_LAYOUT_TYPE will be set to "avutil"

Otherwise,
WEED_CHANNEL_LAYOUT_TYPE will be set to "default" in weed-effects.h



The header also provides compatibility with other libraries, eg. libav. Check the header for details.


== The Ethos of the Weed Effects System ==

Everything in the Weed effects system is designed to make creating a plugin / filter
as simple as possible, whilst allowing the maximum of flexibility for plugin authors.

Any necessary or optional complexity is shifted into the host application which will use the plugins.

The reasons for this are:
- there are expected to be many times more plugins than host applications
- plugins should be kept as small as possible so that less system memory is consumed when opening multiple plugins
- plugin writing should not require too much advanced technical knowledge
- plugins are often abandoned, thus maintaining them when necessary should be kept reasonably simple

on the other hand:
- host applications generally have less rigorous memory requirements
- functionality to handle complex situations can be written once and then applied generically to all plugins
- as much of the functionality as possible is optional. Thus a host can start with the basics and add optional functionality
  as and when needed.






== WEED_FILTER_API_VERSION  ==

This preprocessor symbol is defined as 200 for this version of the specification. This
number may be increased for future revisions of the spec.

libweed-utils exports the following function:

  int check_filter_api_compat(int32_t version_a, int32_t version_b)

which returns WEED_TRUE if the two versions are compatible, WEED_FALSE otherwise.

Compatible means that all of the functions in the lower version are available in the higher version.
The higher version may add new features and definitions which are not available in the lower version.


=== Explanation of Terms ====
Some terms used below have specific definitions.

Initialised: the init_func() (if it exists) has been called for the filter and the instance passed to that function by the
host is now ready for use. Instances created for filters with no init_func() are automatically considered initialised.

Reinit: if a filter_class has no init_func() then this term may be ignored. Otherwise:

- if an instance is not initialised then reinit means calling the init_func() for the filter.
- If the instance IS initialised then reinit means calling the deinit_func() (if present) and then calling the init_func again

- repeatable channels
- optional channels
- disabled channels
- temp disabled channels






For Weed Effects (and Event) plugins, the value of the plant leaf "type" MAY be one of:

  * WEED_PLANT_HOST_INFO          : Information about host and core functions
  * WEED_PLANT_PLUGIN_INFO        : Information about plugin and list of filter classes it includes
  * WEED_PLANT_FILTER_CLASS       : Descriptive information about single filter class
  * WEED_PLANT_CHANNEL_TEMPLATE   : Information about what kinds of channels filter accepts
  * WEED_PLANT_PARAMETER_TEMPLATE : Information about what kinds of parameters filter has
  * WEED_PLANT_FILTER_INSTANCE    : All data about an instance
  * WEED_PLANT_CHANNEL            : Instantiation of a channel
  * WEED_PLANT_PARAMETER          : Instantiation of a parameter

  * WEED_PLANT_GUI                : Used for GUI hints for the
                                    filter_classes and parameter_templates.






== WEED UTILITY FUNCTIONS ==

To make life easier for host and plugin writers, there exists a Weed
utility library, which wraps some of the core functions in simpler
variants. This is documented in the Weed Utility Library spec. (TODO).







=== functions ===
The following functions are defined in weed-effects.h:


== PLUGIN FUNCTIONS ==

The only fixed function name the plugin MUST implement is weed_setup(), with prototype:

    weed_plant_t *weed_setup(weed_bootstrap_f weed_bootstrap)

The host calls this first in a plugin, and passes in a pointer to a function of type weed_bootstrap_f.
(libweed-utils provides a default version of weed_bootstrap which it is recommended to use).


The prototype of weed_bootstrap_f is:

    weed_plant_t *weed_bootstrap(default_getter_f *, int32_t weed_api_min_version, int32_t weed_api_max_version,
     int32_t weed_filter_api_min_version, weed_filter_api_max_version);

The plugin should call the bootstrap function which will check if its versions are compatible with the host, and if so,
create a HOST_INFO plant, which is returned to the plugin, as well as setting a pointer to the default getter function.

On return, the plugin should use the default getter to bootstrap its core Weed functions.
It may then create a PLUGIN_INFO plant and return that to the host.


The precise details of this are described below. weed-plugin-utils.h provides macros to automate handling of all of this.
- a plugin need only call:

WEED_SETUP_START(int weed_api_version, int filter_api_version)

Example:

WEED_SETUP_START(200, 200) { // either sets weed_plant_t *plugin_info, or returns NULL to the host
// set up plugin_info


// .....


// no return necessary
}
WEED_SETP_END;  // returns plugin_info to the host. may be positioned before or after the closing brace. The semi-colon is optional


WEED_SETUP_START also ensures that the weed_setup() function is exported from the plugin on any compatable platform.




If the plugin supports earlier versions than the current version, for example, if the code is updated to take advantage
of newer features which may be added, it may instead use:


WEED_SETUP_START_MINMAX(int min_weed_api_version, int max_weed_api_version, int min_filter_api_version,
int max_filter_api_version)

The original values (or higher) should then be used as the minimum versions,
and the maximum versions set to the current versions at the time of the update.

In this case the plugin should check the actual versions returned from the host to discover which features are available at run time.




==== weed_desetup ====
This is an optional function in for plugins.

    void weed_desetup(void);



If the plugin exports this function, the host MUST call it exactly once before
unloading the plugin. This is to allow the plugin to reset any hardware, free statically allocated memory, etc.

The plugin MUST NOT free any of the standard plants (host_info, plugin_info, filter_classes, channel_templates,
parameter_templates, gui), that job is left to the host to perform.


weed-plugin-utils.h also provides macros to wrap this function:


WEED_DESETUP_START {

// clean up here

//

}
WEED_DESETUP_END; // may be positioned before or after the closing brace. The semi-colon is optional



WEED_DESETUP_START also ensures that the weed_desetup() function is exported from the plugin on any platform.



=== FILTER FUNCTIONS ===

Each plugin may provide one or more FILTER_CLASSES. The functions for a filter class are:


==== init_func ====


    weed_error_t init_func(weed_plant_t *filter_instance)


This is an optional function in the filter_class.


If this function is included in the filter_class,
the host MUST call it exactly once before it can start to use process_func(), passing in the filter instance to be used there.

The filter instance passed by the host MUST have been correctly setup to match the filter class it relates to: 

this means that:

all the mandatory leaves for the instance MUST be set by the host,
all input and output channels must be created (even if they are optional and disabled - with the exception
of optional REPEATABLE channels) and attached to the instance;
the mandatory leaves of all non-disabled input and output channels, MUST be set;
and all input and output parameters MUST be created, their mandatory leaves set, and they MUST be added to the instance.

The host should also endeavour to configure the instance as closely as possible to the values to be used in the process_func(),
e.g setting channel sizes and palettes, initial variable values and so on, to the highest extent possible,
There is no need to set the actual "pixel_data" for the channels however until the process_func is actually called.

The init_func() function allows the plugin to create any internal
memory structures it needs; the plugin can store internal data in inst as
leaves that have keys prefixed with "plugin_" in the filter_instance 
(see the definition of filter_instance plant).

The plugin can also (optionally) (re)set the "gui" settings for parameters (see below),
perhaps setting HIDDEN and COPY_VALUE_TO leaves.

the plugin may fully define the "choices" for a string list type parameter (see below).

The function returns WEED_SUCCESS or an error code (see below). 



==== process_func ====

   weed_error_t process_func(weed_plant_t *filter_instance, weed_timestamp_t timestamp)

This is an optional function in the filter_class.

Ths host may call this as often as it wishes after calling the init_func (if applicable).

Host calls this for each processing cycle; the plugin should process the in parameters and non-disabled in channels (if they exist) and
produce data in the non-disabled out channels and optionally the out parameters (if they exist).

Timestamp is nominally in units of 10 ^ -8 (100 millionth) of a second 'since playback started'.
Normally it will increase monotonically for each frame but that is not guaranteed,
although hosts should attempt to keep it so between calling init_func() and deinit_func(). In case the filter cannot handle
non-monotonic timecodes, it may return WEED_ERROR_NEEDS_REINIT if such an event occurs.

The host must pass the same or an exact copy of, the instance passed to the plugin in the init_func()
(if applicable). [There are a couple of exceptions to this rule for threading, as explained below].

The function returns WEED_SUCCESS or another error code (see below). 



==== deinit_func ====
This is an optional function in the plugin. If present, the host must call it exactly once after running the init_func,
and completing its processing run.


    weed_error_t deinit_func(weed_plant_t *filter_instance)

The host MUST pass in the same or an exact copy of, the instance used in in init_func() and process_func().
[again with the minor exception for threading]

Following this the host may call the init_func() again (if applicable)
either with the same instance or a different one created from the same filter class,
Otherwise it may call the desetup function, and free the following if no longer required:
host_info, plugin_info, any filter_classes and their component  channel_templates, parameter_templates
and associated GUI plants.

The plugin MUST NOT free any of the standard plants (host_info, plugin_info, filter_classes, channel_templates,
parameter_templates, gui), that job is left to the host to perform.




Less commonly used functions:



==== interpolate_func ====
T.B.D




== HOST FUNCTIONS ==

The host provides just one mandatory function to the plugins:

weed_bootstrap (see above for its definition).

The bootstrap function takes as parameters the min /max Weed ABI versions and min / max Filter API supported by the plugin,
The host should check the ranges  for compatibily with the versions that the it supports. In case of a mismatch,
NULL should be returned to the plugin, and the plugin should not be used.

The bootstrap func also creates a HOST_INFO plant which is returned to the plugin. The host MUST set pointers to all the Weed core
functions for the plugin to use. The exact functions may vary depending on the ABI level agreed upon between plugin and host.
The host may use standard library functions, or may choose to overload functions for the plugin.

The bootstrap function also takes a further parameter, a pointer to a "default_getter" function.
The plugin will use this function to bootstrap its normal Weed core functions, which it will retreive from the host_info plant.

The default_getter should use only standard memory functions malloc, memcpy and free, since the plugin needs to bootstrap
weed_malloc, weed_memcpy and weed_free. The plugin should also retrieve the Weed and Filter API versions agreed upon with the
host, in order to ascertain the set of core funstions available. Having done so, the plugin can now retrieve the normal getter function
(e.g weed_leaf_get() for Weed ABI version 200) and either use that or the default getter to retrieve the remaining core functions.

The host may optionally also create a PLUGIN_INFO plant for the plugin and attach this to the HOST_INFO.

The HOST_INFO plant also has optional leaves which may be set to provide more information about the host and its
capabilities.

libweed-utils provides an implementation of weed_boostrap which performs all of the host part of the setup. The host may pass
a pointer to this function to plugin when calling weed_setup() in the plugin. The library version of weed_bootstrap also provides
a callback function which allows the host to customize the host_info plant before it is returned to the plugin.




=== Re-entrancy ===

Plugins should be re-entrant, i.e the host should be able to create multiple instances from the filter class,
provided each instance follows the rules for init_func(), process_func(), deinit_func().

This means that a plugin should only maintain data common to all instances locally (i.e static variables).
The data for each separate instance should be stored inside the instance itself.

If this is not possible for a filter class, the plugin should export init_func() and deinit_func() and return 
WEED_ERROR_TOO_MANY_INSTANCES if the host atempts to pass a second filter instance to the init_func() without deiniting the
first.




=== Multiple filters in one plugin ===

A plugin may provide multiple filters amd include them all as an array in the plugin_info.

Each filter should have its own set of in_parameter_templates, out_parameter_templates,
in_channel_templates and out_channel_templates and any related gui plants. Even if the values contained within are identical,
each filter MUST have its own set.


The weed-plugin-utils code provides a function:

* weed_clone_plants

which takes as input an array of plants and produces a copy, including producing new gui plants. as appropriate.



== PLANT TYPES ==

There now follows a description of the various plant types for weed effects, 
and their mandatory and optional leaves.

Note that whilst the "raw" values of the leaves are given, all of them have a more "user-freindly"
version, e.g. WEED_LEAF_NAME can be used in code instead of "name".

(TODO - document the equivalent names)



== PLANT TYPE HOST_INFO ==

This plant is created and returned in the weed_bootstrap function which the plugin MUST call from its weed_setup().

If weed_boostrap() from the weed-utils library is passed as the parameter to weed_setup(),
then the host_info will be created automatically using default values. The default values used for the Weed ABI and filter API will be
whatever versions the library was compiled with.

The host can choose to implement its own weed_bootstrap and create its own host_info,
or if using the function from libweed-utils it may optionally set a host_info callback. The host_info plant can be adjusted - the host
may choose to use different ABI / API levels, may optionally override any of the core functions for the plugin, and may
provide more information about itself for the plugin's use (See the description of host_info). The host may also, if it wishes, create
the plugin_info plant for the plugin to use and attach it as a leaf to the host_info. The host may also provide its own implementation
of the default get function, which the plugin will use to bootstrap its normal functions, or the implementation in libweed-utils may be
used.



 * "type" == WEED_PLANT_HOST_INFO

'''Mandatory leaves''':

As of the current Weed ABI (200) and Filter API (200) versions


WEED_LEAF_MALLOC_FUNC "weed_malloc_func"  :: WEED_SEED_FUNCPTR :
		      			     		       a pointer to the weed_malloc() function which the plugin shouid use. May be the standard
							       malloc() function, or a customised function selected by the host.

WEED_LEAF_FREE_FUNC "weed_free_func" :: 
		      			     		       a pointer to the weed_free() function which the plugin shouid use. May be the standard
							       malloc() function, or a customised function.


							       			       etc.
WEED_LEAF_MEMSET_FUNC "weed_memset_func"

WEED_LEAF_MEMCPY_FUNC "weed_memcpy_func"

WEED_LEAF_CALLOC_FUNC "weed_calloc_func"

WEED_LEAF_REALLOC_FUNC "weed_realloc_func"

WEED_LEAF_MEMMOVE_FUNC "weed_memmove_func"

-----------

WEED_PLANT_NEW_FUNC "weed_plant_new_func"

WEED_PLANT_FREE_FUNC "weed_plant_free_func"

WEED_LEAF_GET_FUNC "weed_leaf_get_func"  :: WEED_SEED_FUNCPTR - pointer to function of type weed_leaf_get_f for the plugin to use

WEED_LEAF_SET_FUNC "weed_leaf_set_func"       :: etc...

WEED_LEAF_DELETE_FUNC "weed_leaf_delete_func"       :: etc...

WEED_LEAF_NUM_ELEMENTS_FUNC "weed_leaf_num_elements_func"

WEED_LEAF_ELEMENT_SIZE_FUNC "weed_leaf_element_size_func"

WEED_LEAF_SEED_TYPE_FUNC "weed_leaf_seed_type_func"

WEED_LEAF_GET_FLAGS_FUNC "weed_leaf_get_flags_func"

WEED_PLANT_LIST_LEAVES_FUNC "weed_plant_list_leaves_func"



 * "weed_api_version" : WEED_SEED_INT : weed abi version exposed in host,

 * "filter_api_version" : WEED_SEED_INT : filter api version provided by host




'''Optional leaves''': [[BR]]

 * "plugin_info" : WEED_SEED_PLANTPTR : the host may opt to create the plugin_info for the plugin in the bootstrap function.
   		   		      	    	     	    	   Thus the plugin should check the value of this leaf after calling the bootstrap
								   function and use the plant provided rather than creating a new one.
								   (Most likely the plugin will use a utility function which will call the bootstrap function
								   and retrieve this leaf before returning it to the plugin)


 * "host_name"    : WEED_SEED_STRING : host name


 * "host_version" : WEED_SEED_STRING : host version


 * "flags"        : WEED_SEED_INT    : bitmap of host_info flags (see below)


 * "layout_schemes" : WEED_SEED_STRING : an array of layout schemes that the host supports (see below, "layout_scheme")


* "verbosity" : WEED_SEED_INT : plugins should check the value of this leaf and produce debug / error / info messages accordingly.
  	      		      		       	     (preferably on STDERR / cerr). See below for the defined values and interpretations.
						     If the leaf does not exist, then the plugin may assume a value of either
						     WEED_VERBOSITY_ERROR or WEED_VERBOSITY_WARN (author's discretion).



The host may add any number of additional leaves, but it is recommended that it use keys prefixed "host_" to avoid
possible conflicts with future versions of the spec.


The plugin must not add, delete  or alter any leaves in this plant.




== PLANT TYPE PLUGIN_INFO ==

The plugin_info plant should be created by plugin in weed_setup() after receiving the host_info plant from weed_bootstrap()

IF the host_info has a plugin_info leaf, then the plugin MUST use the value set there, rather than creating a new plant.

The plugin may opt to call weed_plugin_info_init() (provided in weed-plugin-utils) instead,
passing weed_bootstrap as a parameter; in which case weed_bootstrap() will be run for it, the core functions retrieved,
and if the returned host_info plant contains a plugin_info leaf, this will  partially setup and then returned the plugin_info() plant.
Otherwise a new plugin_info plant will be  intitialized and attached to the host_info before being returned.

The WEED_SETUP_START macro defined in weed-plugin-utils.h also calls weed_plugin_info_init() providing a convenient wrapper for
most plugins to use.




The plugin should set up the remaining leaves of that plant and then return it to the host from weed_setup().

Plugin info describes the filter classes which are available in the plugin.

After receiving the plant, the host may set all leaves in it IMMUTABLE / UNDELETABLE
and should not change any leaf values itself, except:

The plugin may add any nuber of additional private leaves with keys prefixed "plugin_"

If the host adds additional leaves, it is recommended that the be prefixed with "host_" to avoid possible conflicts with future
versions of the spec.



 * "type" == WEED_PLANT_PLUGIN_INFO

'''Mandatory leaves''':[[BR]]

 * "filters"	  : WEED_SEED_PLANTPTR : array of pointers to the filters in the plugin. In case of a fatal error during weed_setup(),
   		    		       	       	  	   the plugin should set this to NULL, and set the error leaves as described
							   below.

 * "version"	  : WEED_SEED_INT : plugin package version

 * "host_info"	  : WEED_SEED_PLANTPTR : pointer to the HOST_INFO plant returned by weed_bootstrap() which contains information
                                         about the host. If not already present, the plugin MUST set this when creating the plugin_info,
					 (the host may opt to use a standard bootstrap function which creates the plugin_info for the plugin
					 and sets this automatically. In addition, if the plugin is using standard library functions then this leaf will
					 be set automatically anyway).

					 Even in the case of fatal error during the plugin setup, it is essential to still set this leaf so that the host
					 may free both the plugin_info and host_info plants.


'''Optional leaves''':[[BR]]


 * "package_name" : WEED_SEED_STRING : for wrapper filters, the name of the package which is wrapped
 Package names are case insensitive and may consist only of alphanumeric characters plus '_'.
 Some package names are reserved and should not be used generally (see below, "hasnames" for examples).


 * "maintainer"	  : WEED_SEED_STRING : maintainer(s) of plugin package

 * "url"	  : WEED_SEED_STRING : URL of plugin package

* "description" : WEED_SEED_STRING : description of the package, free form text, 
	       			       	    	 	    May contain multiple elements, in which case each value may be prefixed by an IETF language
							    code followed a colon and a space, eg. "en_US: foo", "pt_BR.utf-8: bar"


The following may be set inside the weed_bootstrap() function from the values supplied by the plugin:

 * "min_weed_api_version"      : WEED_SEED_INT        :: min version of the Weed API that the plugin supports

 * "max_weed_api_version"      : WEED_SEED_INT     :: etc

 * "min_weed_filter_version"   : WEED_SEED_INT

 * "max_weed_filter_version"   " WEED_SEED_INT



In case of a fatal error during weed_setup() e.g. a needed library is missing, there are various things the plugin can do:
1) check the host verbosity, and if it is greater than WEED_VERBOSITY_SILENT, write an error message to STDERR
2) return a NULL plugin_info
or:
3) return a plugin_info with "filters" absent or set to NULL
and set one or both of the following leaves in the plugin_info:

"error_code" : WEED_SEED_INT :: a standard Weed error code, possible values include: WEED_ERROR_MEMORY_ALLOCATION,
	       		     	WEED_ERROR_BADVERSION, WEED_ERROR_PLUGIN_INVALID, WEED_ERROR_FILTER_INVALID,
				WEED_ERROR_TOO_MANY_INSTANCES.

"error_text" : WEED_SEED_STRING : free form text describing the error, e.g "Unable to find configuration files"
	       			       	    	 	    May contain multiple elements, in which case each value may be prefixed by an IETF language
							    code followed a colon and a space, eg. "en_US: foo", "pt_BR.utf-8: bar"


Option 1 is highly recommended, regardless of the other choices.
Option 4 allows for a more precise definition of the failure reason, as well as internationalization of the error text.
If neither of these are considered necessary then option 2 provides a simpler alternative.




== PLANT TYPE FILTER_CLASS ==

Plant type filter_class is used to describe all properties of a single
filter in a plugin. It is created by the plugin in weed_setup() and
then added to the plugin_info plant.

Values in the plant should not be altered after weed_setup(),
but plugin and host may add private leaves with keys prefixed "plugin_" and "host_" respectively.

"type" == WEED_PLANT_FILTER_CLASS

'''Mandatory leaves''':[[BR]]

 * "name"         : WEED_SEED_STRING : the filter name; should be unique in the plugin.
   		    Technically, the name need not be unique, provided each version has a different
		    'author' (see hashnames, below).
		    However, to avoid confusion, it is recommended to use unique filter names
		    whenever possible.

 * "author"       : WEED_SEED_STRING : the filter author(s) - CHANGING THIS WILL CREATE A DIFFERENT
   		    FILTER; instead update the "extra_authors" leaf (see below). For wrapper type
		    plugins, this may be set to e.g. "<package_name> Authors", and the
		    "extra_authors" leaf may be used to set individual filter author names.

 * "version"      : WEED_SEED_INT : filter version.

  		   Adding (appending) more parameters (in or out) or appending extra optional channels
   		    		    does not require a version update.


		    However, removing parameters, changing 
   		    their order or type, adding mandatory channels or removing channel templates does
		    require an update.

		    Prior versions of the filter may still be exported by the plugin,

		    If a parameter is removed, then the flag bit
		    WEED_PARAMETER_VALUE_IRRELEVANT may be set in the parameter template in prior
		    filter versions, so that the
		    host can avoid wasting resources by recording / setting the value of the unused
		    parameter, and
		    additionally "hidden" may be set to WEED_TRUE in the template GUI plant(s) to
		    hint to the host not to display
		    the unused parameter in interaces.

		    In the case of multiple versions of the same filter, the plugin should
		    retrieve the value of the "filter_class"
		    leaf of the instance and from that it can obtain the "version" which the host
		    selected.

		    Changes which do not require a new version:
		    	    - appending parameters (in or out)
			    - appending optional channels (including increasing MAX_REPEATS)
			    - adding extra palettes to a channel template "palette_list"
			    - changes to *_REINIT_ON_* flags (but note, this may cause visual
			      changes within the host)
			    - setting (but not unsetting) WEED_PARAMETER_VALUE_IRRELEVANT,
			      WEED_PARAMETER_VARIABLE_SIZE
			    - changing the 'default' or 'new_default' of a parameter
			    - extending the range of 'min', 'max'
			    - settting / unsetting WEED_CHANNEL_CAN_DO_INPLACE,
			    WEED_FILTER_HINT_STATELESS,
			    WEED_FILTER_HINT_MAY_THREAD, WEED_FILTER_PREF_PREMULTIPLIED_ALPHA,
			    WEED_FILTER_PREF_LINEAR_GAMMA


			    In these cases, the plugin developers may choose to update the filter
			    "version" or not. Otherwise, the "micro_version" leaf should be
			    increased instead.



Mandatory for filters with video channels

 * "palette_list" : WEED_SEED_INT : the plugin sets this to an array of allowed palettes for channels created from channel templates
   for the filter. It should contain as many palettes as possible that the filter may handle.
   The palettes should be listed in order of preference (i.e those which can be processed faster should be listed first).
   The list may optionally be terminated with WEED_PALETTE_END.



'''Optional leaves''': [[BR]]

 * "flags"        : WEED_SEED_INT : bitmap of filter flags (see below)

* "process_func" : WEED_SEED_FUNCPTR : pointer to the process_func()

* "init_func"    : WEED_SEED_FUNCPTR : pointer to the init_func()
                    (can also be NULL)

* "deinit_func"  : WEED_SEED_FUNCPTR : pointer to a the deinit_func()
                    (can also be NULL)

* "in_chan_tmpls"    : WEED_SEED_PLANTPTR, list of 0 or more elements: array of in channel templates,
  '''type''' of the referenced plants MUST be  WEED_PLANT_CHANNEL_TEMPLATE

* "out_chan_tmpls"   : WEED_SEED_PLANTPTR, list of 0 or more elements : array of out channel templates, '
  ''type''' of the referenced plants MUST be  WEED_PLANT_CHANNEL_TEMPLATE

* "in_param_tmpls"  : WEED_SEED_PLANTPTR, list of 0 or more elements : array of in parameter templates,
  '''type''' of the referenced plants MUST be  WEED_PLANT_PARAMETER_TEMPLATE

* "out_param_tmpls" : WEED_SEED_PLANTPTR, list of 0 or more elements : array of out parameter templates, '
  ''type''' of the referenced plants MUST be  WEED_PLANT_PARAMETER_TEMPLATE.



 * "micro_version" : WEED_SEED_INT : an optional value which may be increased to denote minor
   		     		     updates which do not break backwards compatibility.
				     May be reset to 1 or 0 when a new "version" is released.
				     If not present, a value of 0 is assumed.

 * "extra_authors": WEED_SEED_STRING : list of extra authors which can be altered without
   		    		       creating a new filter.

 * "description"  : WEED_SEED_STRING : filter description, free text
	       			       	    	 	    May contain multiple elements, in which case each value may be prefixed by an IETF language
							    code followed a colon and a space, eg. "en_US: foo", "pt_BR.utf-8: bar"

 * "url"          : WEED_SEED_STRING : filter URL, free text

 * "copyright"    : WEED_SEED_STRING : copyright details for filter, free text

 * "license"      : WEED_SEED_STRING : license of filter, free text

 * "preferred_fps"   : WEED_SEED_DOUBLE : plugin may hint to the host the preferred display rate for the
                                       host to run the filter; for example if the filter is designed to run best at 25 fps, then the value 25.0
				       may be set. Note that this is only a hint to the host, there is
				       no guarantee that the host will comply with this.

 * "gui" : WEED_SEED_PLANTPTR : pointer to a plant
           type GUI [see below - GUI plants]. The plugin may optionally create and populate one GUI plant per filter in weed_setup().


the following are optional for filters with video channels:

* "width" : WEED_SEED_INT    :
  For filters that require fixed frame sizes. The host MUST set channel pixel widths to this value in order to use the filter, otherwise
  the plugin may return WEED_ERROR_REINIT_NEEDED from it process_func().

  May contain more than one element, in which case the host is free to choose from among the choices provided.
  If multiple values are defined, they should be listed in descending order of magnitude to assist the host selecting in the best match.

  The plugin should ONLY set this if it is absolutely necessary for the filter to function.
  If it is possible to use some combination of "maxwidth", "minwidth",
  "hstep" and "alignment_hint" to achieve the same result, then those leaves should be used in preference.

  (The value here is measured in pixels so the actual value of "width" in channels may vary depending on the palette chosen,
  since there the width there is measured in MACRO pixels (i.e for WEED_PALETTE_UYVY and WEED_PALETTE_YUYV,
  1 macropixel == 2 actual pixels; for WEED_PALETTE_YUV411, 1 macropixel = 4 actual pixels). However this is only relevant
  when converting from one palette to another.

  For planar palettes the value(s) define the allowed pixel width(s) of the first plane.

  If "height" is also set, then that leaf MUST contain EITHER one value, or an equal number of values to this one,
  and them combined set of values shall be understood to form sequential pairs.

  If the flag WEED_FILTER_CHANNEL_SIZES_MAY_VARY is set for the filter, then this value may be overriden for individual
  channels. Setting a value <= zero there means that that particular channel has no width limitations.



 * "height" : WEED_SEED_INT   :
  For filters that require fixed frame sizes. The rules are similar to those for width.

  If this leaf contains multiple elements then height values matching the same width (or no width) MUST be listed in
  ASCENDING ORDER OF MAGNITUDE (ie. smallest to largest) to assist the host in selecting the best match.

  e.g: 	width values:		128,		256,   	480,		480,		480,		640,		640,		640
       		height values:		128,       	256,		240,		320,		480,		320,		480,		640


Examples:
	fixed size:
	 	width value:		640
       		height value:		480

	width restricted, height unrestricted:
	 	width value:		1280
       		height value:		-
or:		
 	 	width values:		128,		256,   	640,		1024,	2048
       		height value:		-

	width unrestricted, height unrestricted:
	 	width value:		-
       		height value:		1280
or:
	 	width value:		-
	 	height values:		128,		256,   	640,		1024,	2048

	pairs:
	 	width values:		128,		256,   	480,		480,		480,		640,		640,		640
       		height values:		128,       	256,		240,		320,		480,		320,		480,		640




 * "hstep" : WEED_SEED_INT : If set, the host must set the widths of each channel to a multiple of this.
   	     		     	     	      Should be avoided if possible for performance reasons.
					      The value is ignored if "width" is set for the filter.

  The value is measured in pixels; the macropixel size will be some multiple of this
   For planar palettes the widths of ALL planes must be an integer multiple of this value.

   The value is fixed for the filter, it cannot be overriden for individual channels, even If the flag
   WEED_FILTER_CHANNEL_SIZES_MAY_VARY is set.

   if not set then a value of 1 may be assumed by the host.



 * "vstep" : WEED_SEED_INT : If set, the host must set the heights of each channel to a multiple of this.
   	     		     	     	      Should be avoided if possible for performance reasons.
					      The value is ignored if "height" is set for the filter.

   For planar palettes the heights of ALL planes must be an integer multiple of this value.

   The value is fixed for the filter, it cannot be overriden for individual channels, even If the flag
   WEED_FILTER_CHANNEL_SIZES_MAY_VARY is set.

   if not set then a value of 1 may be assumed by the host.



 * "alignment_hint" : WEED_SEED_INT :

 If set, the host should attempt to align each plane in the "pixel_data" of each channel to this many bytes boundary.
 In addition it ahould attempt to make the rowstrides in each plane be an integer multiple of this value.
 If "hstep" is set then this value MUST be a multiple of "hstep".

  The value is fixed for the filter, it cannot be overriden for individual channels,
  even If the flag WEED_FILTER_CHANNEL_SIZES_MAY_VARY is set.

   if not set then a value of 1 may be assumed by the host.



 * "maxwidth" : WEED_SEED_INT : If set, the host must set channel widths <= maxwidth (in pixels)

  The value is measured in pixels so the maximum value in channels may be less depending on the palette chosen,
  since there the width is measured in macropixels (i.e for WEED_PALETTE_UYVY and WEED_PALETTE_YUYV,
  1 macropixel == 2 screen pixels, for WEED_PALETTE_YUV411, 1 macropixel = 4 screen pixels).

  For planar palettes the value defines the maximum pixel width of the first plane.

  If the flag WEED_FILTER_CHANNEL_SIZES_MAY_VARY is set for the filter, then this value may be overriden for individual
  channels. Setting a value <= zero there means that that particular channel has no maximum width limitation.

  In all other cases, "maxwith" MUST be >= "minwidth" + "hstep"




* "maxheight" : WEED_SEED_INT : If set, the host must set the channel heights <= maxheight

  For planar palettes, the value defines the maximum height of the first plane.

  If the flag WEED_FILTER_CHANNEL_SIZES_MAY_VARY is set for the filter, then this value may be overriden for individual
  channels. Setting a value <= zero there means that that particular channel has no maximum height limitation.

  In all other cases, "maxheight" MUST be >= "minheight" + "vstep"



 * "minwidth" : WEED_SEED_INT : If set, the host must set channel widths >= minwidth (in pixels)

  The value is measured in pixels so the minimum value in channels may be less depending on the palette chosen,
  since there the width is measured in macropixels (i.e for WEED_PALETTE_UYVY and WEED_PALETTE_YUYV,
  1 macropixel == 2 screen pixels, for WEED_PALETTE_YUV411, 1 macropixel = 4 screen pixels).

  For planar palettes the value defines the minimum pixel width of the first plane.

  If the flag WEED_FILTER_CHANNEL_SIZES_MAY_VARY is set for the filter, then this value may be overriden for individual
  channels. Setting a value <= zero there means that that particular channel has no minimum width limitation.

  In all other cases, "minwidth" MUST be > 0 and <= "maxwidth" - "hstep"



* "minheight" : WEED_SEED_INT : If set, the host must set the channel heights >= minheight

  For planar palettes, the value defines the minimum height of the first plane.

  If the flag WEED_FILTER_CHANNEL_SIZES_MAY_VARY is set for the filter, then this value may be overriden for individual
  channels. Setting a value <= zero there means that that particular channel has no maximum height limitation.

  In all other cases, "minheight" MUST be > 0 and <= "maxheight" - "vstep"




 * "YUV_sampling"     : WEED_SEED_INT : Preferred sampling type for YUV palettes, as defined below.
   		      		      		      	       Be aware that some hosts may not be able to comply with this,
							       so the actual value in the channels should be checked,
							       and if necessary, WEED_ERROR_FILTER_INVALID may be returned.

							       if the filter sets the flag WEED_FILTER_PALETTES_MAY_VARY this default
							       value may be overriden for individual channel templates.
							       Valid only for in_channels. For out channels, the plugin should just set
							       the value in the channel.

 * "YUV_clamping"     : WEED_SEED_INT : Preferred clamping type for YUV palettes, as defined below. 
    		      		      		      	       Be aware that some hosts may not be able to comply with this,
							       so the actual value in the channels should be checked,
							       and if necessary, WEED_ERROR_FILTER_INVALID may be returned.

							       if the filter sets the flag WEED_FILTER_PALETTES_MAY_VARY this default
							       value may be overriden in individual channel templates. 
							       Valid only for in_channels. For out channels, the plugin should just set
							       the value in the channel.


 * "YUV_subspace"     : WEED_SEED_INT : Preferred subspace for YUV palettes, as defined below.
   		      		      		      	       Be aware that some hosts may not be able to comply with this,
							       so the acutual value in the channels should be checked.
							       and if necessary, WEED_ERROR_FILTER_INVALID may be returned.

							       if the filter sets the flag WEED_FILTER_PALETTES_MAY_VARY this default
							       value may be overriden in individual channel templates. 
							       Valid only for in_channels. For out channels, the plugin should just set
							       the value in the channel.




 * Every plugin can store internal data in leaves inside the
   filter_class  plant, and host MUST NOT change their values. Those internal leaves MUST have keys prefixed with "plugin_"


 * The host may add any additional keys required, but it is recommended that the keys be prefixed with "host_"




== PLANT TYPE CHANNEL_TEMPLATE ==

Plant type channel template is used as a description of a single channel (input or output) a filter can handle.
The plugin must not alter any leaves after weed_setup(), except it may add its own leaves with keys prefixed "plugin_",
which the host must not alter.

Note:
By default, ALL channels (in and out) MUST have the same size (width X height). However the rowstrides of each channel may vary.
ALL channels must also have the same palette.

Various flags (*VARY*) may alter this as well as *REINIT_ON*




 * "type" == WEED_PLANT_CHANNEL_TEMPLATE

'''Mandatory leaves for all channels''': [[BR]]

 * "name" : WEED_SEED_STRING  : name of the channel, MUST be unique across all channels (in and out) in the filter class
   	    		      	     	    	     names may be generic (e.g. "in_channel0") or more specific (e.g "alpha layer (optional)")

'''Additional Mandatory leaves for channels with video''': [[BR]]

None.


'''Additional Mandatory leaves for channels with audio''': [[BR]]

 See the weed AUDIO extension.



'''Optional leaves for all channel types''': [[BR]]

 * "flags" : WEED_SEED_INT : bitmap of channel_flags that plugin sets

 * "description"  : WEED_SEED_STRING : description of this channel
	       			       	    	 	    May contain multiple elements, in which case each value may be prefixed by an IETF language
							    code followed a colon and a space, eg. "en_US: foo", "pt_BR.utf-8: bar"

 * "max_repeats" : WEED_SEED_INT : This is an important leaf, as it informs the host that it may create multiple channels from the
   		   		   	template. If absent then a default value of 1 is assumed.


					A value of 0 indicates any number (limitless) copies of this channel may be created by the host,.

					If the channel_template flagbit WEED_CHANNEL_IS_OPTIONAL is also set, then the MINIMUM number of this
      					channel_template is 0; otherwise it is 1.

      					If "max_repeats" is present, then it must be possible for any of the channels created from this template
      					to be marked / umarked as "disabled" by the host between processing calls without the need to re-initialise
					the plugin.

      					This is permitted even if the template is not marked "optional" - though in that case the number 
      					of non-disabled repeats MUST always be at least 1.

       					Channels which are disabled in this way will still be present in the channel array for the instance,
       					but their "pixel_data" may be set to NULL.


       Altering the TOTAL NUMBER of repeats (disabled + non-disabled) requires a reinit of the plugin.

      The leaf is valid for BOTH in and out channel templates.





 * Every plugin can have its internal data stored in leaves inside this plant, and host MUST NOT change their values or make them
 READONLY for the plugin. Those internal leaves MUST have keys prefixed with "plugin_"

 * The host may add any additional keys required, but it is recommended that the keys be prefixed with "host_"




'''Optional leaves for channels with video''': [[BR]]

  If the filter flagbit WEED_FILTER_CHANNEL_SIZES _MAY_VARY, then the following leaves may be set
  to define values for channels created from an individual template. Values set here override any defaults set in the filter_class.
  A value of zero may be used to indicate that the channel(s) created from this template are not restricted by
  the defaults set for the filter.

  For more details, see the definitions in filter_class.

  NOTE:
  "hstep", "vstep" and "alignment_hint" can ONLY be set in the filter_class, and may not be overriden for
  individual channels.


 * "width" : WEED_SEED_INT    :  overrides any default set in the filter class. A value of zero means no limitations.

 * "height" : WEED_SEED_INT   : overrides any default set in the filter class. A value of zero means no limitations.

 * "maxwidth" : WEED_SEED_INT : overrides any default set in the filter class. A value of zero means no limitations.

 * "maxheight" : WEED_SEED_INT : overrides any default set in the filter class. A value of zero means no limitations.

 * "minwidth" : WEED_SEED_INT :  overrides any default set in the filter class. A value of zero means no limitations.

 * "minheight" : WEED_SEED_INT : overrides any default set in the filter class. A value of zero means no limitations.



  If the filter class flagbit WEED_FILTER_PALETTES _MAY_VARY is set, then the following leaves may be set
  to define values for channels created from an individual template. Values set here override any defaults set in the filter_class.

  For nore details, see the definitions in filter_class.

 * "palette_list" : WEED_SEED_INT - ARRAY : overrides any default set in the filter class.

 * "YUV_sampling"     : WEED_SEED_INT : overrides any default set in the filter class.

 * "YUV_clamping"     : WEED_SEED_INT : overrides any default set in the filter class.

 * "YUV_subspace"     : WEED_SEED_INT : overrides any default set in the filter class.



 * "natural_size" : WEED_SEED_INT[2]

if the plugin sets the channel_template flagbit WEED_CHANNEL_NEEDS_NATURAL_SIZE, then the host
should set this to the width
and height in pixels (NOT macropixels) of the channel BEFORE without any resizing.
This is to allow for example fixed size objects to
be properly scaled regardless of the scaled channel size. See also the notes for the flagbit.
If the leaf is not set, then it should be assumed that the current size is also the natural size.




'''Optional leaves for channels with audio''': [[BR]]

 See the weed AUDIO extension.







== PLANT TYPE PARAMETER_TEMPLATE ==

Plant type parameter_template is used as a description of a single
parameter (input or output) filter can handle. All leaves SHOULD be set readonly for the plugin by the host after
weed_setup(). Host should only change the "default" value to a valid
value for the parameter. The host should not change any other leaves.

 * "type" == WEED_PLANT_PARAMETER_TEMPLATE

'''Mandatory leaves''': [[BR]]

* "name" : WEED_SEED_STRING  : name of the parameter, MUST be unique across the in_parameters/out_parameters


 * "param_type" : WEED_SEED_INT : subdivides parameters into different types  [see below]


* "default" :           suggested default value(s) of the parameter :
  	    		     for in parameters, MUST contain exactly ONE value of the correct seed_type
  	    		     UNLESS the template has the WEED_PARAMETER_VARIABLE_SIZE flag set, in which case this leaf is optional,
			     and may contain any number of elements; in the case of COLOR parameters the number MUST be an integer
			     multiple of the value size (3 for RGB, 4 for RGBA).

			     For out parameters this leaf may contain at least zero values (zero values meaning just the seed_type is set).

			     For in parameters where the template has the flag WEED_PARAMETER_VALUE_PER_CHANNEL set, the "default"
			     is applied to each value.



 * "new_default" :  MANDATORY for in parameters which have the flag WEED_PARAMETER_VARIABLE_SIZE set.
   		 	     Suggests the default value to be used by the host when adding new additional values to the parameter.






'''Optional leaves''':[[BR]]

* "flags"            : WEED_SEED_INT : bitmap of parameter template flags

 * "description"      : WEED_SEED_STRING : parameter description
	       			       	    	 	    May contain multiple elements, in which case each value may be prefixed by an IETF language
							    code followed a colon and a space, eg. "en_US: foo", "pt_BR.utf-8: bar"

* "interpolate_func" : TODO


* "copy_value_to" : WEED_SEED_INT : index (0 means first parameter, 1 means second, etc.)
   of another in_parameter : hint to the host that if the "value" of this parameter is changed, then the
   "value" of the parameter pointed to should be set the same by the host.

  Both parameters source and target MUST have the same PARAM_TYPE and seed_type. 

    - if the source parameter has variable size, then this is only valid if the target parameter also has the flag bit set

    - if the target parameter has a value per channel and the source does not, then the source value sould be duplicated to each channel

    - if the source parameter has one element per channel, then this is only valid if the target parameter also has that
      flag bit set, or if it has variable elements.



   in all other cases this flag bit may be ignored.

   - If more than one source parameter points to the same target parameter, the behaviour is undefined.

   - Since multiple parameters can have this leaf set, the host should keep track of which parameters have been adjusted
   and take care to update each parameter no more than once per processing cycle, in order to avoid the
   possibility of becoming stuck in a loop.

   NOTE:
   The value here (if any) is considered a permanent (structural) setting.
   If the plugin wants to set temporary hints to copy values of parameters during processing,
   then it may create a leaf with the same name within the parameter GUI plant and update it during its init_func(). (See below).

   Example: a plugin creates a filter which overlays text on a frame, and it has two color values, text color and outline color.
   The outline color should default to being equal to the text color. The plugin achieves this by setting "copy_value_to"
   in the template of the "text_color" parameter to point to the index of the "outline_color" parameter.




 * "gui" : WEED_SEED_PLANTPTR : each parameter_template (for in_parameters) can have a
   	   		      "gui" leaf. This leaf points to a plant of type
 			      	    GUI. Within the GUI plant can be additional leaves to assist the host
 				    to display this particular parameter. The plugin can create it, and
				     set leaf values in it in weed_setup(). Host which are not displaying an interface for the
				     filter may ignore this leaf entirely.
				     




 * Every plugin can have internal data stored in leaves inside this plant, and host MUST NOT change their values or make them
 READONLY for the plugin. Those internal leaves MUST have keys prefixed with "plugin_".

 * The host may add any additional keys required, but it is recommended that the keys be prefixed with "host_"



==== PARAMETER TYPES ====

The "param_type" is a mandatory WEED_SEED_INT leaf of every parameter; the defined values are:

 * WEED_PARAM_UNSPECIFIED
 * WEED_PARAM_INTEGER
 * WEED_PARAM_FLOAT
 * WEED_PARAM_TEXT
 * WEED_PARAM_SWITCH
 * WEED_PARAM_COLOR

Depending on the value of "param_type", additional leaves may be defined for that parameter tmeplate.

 * WEED_PARAM_UNSPECIFIED
   Parameter is of an unknown type. Plugins should never use this
   by choice, it is intended only for wrapper plugins which may need to
   enumerate out of scope parameter types. These parameter types MUST have at least "name" set, and may optionally
   set any of the other standard leaves when possible to extract their values.
   The principle purpose is so that the indexing of Weed filter parameters matches with the indexing of the wrapped filter.
   Consider also creating a GUI leaf for the template and setting "hidden" to WEED_TRUE for such parameter types, to hint
   to the host not to display the parameter in user interfaces.


 * WEED_PARAM_INTEGER

"value" and "default" are constrained by min and max: min <= value <= max
The "default" leaf can only be of seed type WEED_SEED_INT. "default"
may have any number of elements  > 0.
0 elements in the default is only allowed for variable sized values, and "new_default" must be defined then.

 == mandatory ==

 * "min" : WEED_SEED_INT : minimal value of the parameter, MANDATORY for in parameters (optional for out parameters)

 * "max" : WEED_SEED_INT : maximal value of the parameter, MANDATORY for in parameters (optional for out parameters)

   Note that although these are mandatory they are still only hints. The host may ignore them and the
   plugin must not assume that data supplied to it is meaningful. If
   the plugin receives invalid input data it is expected to continue
   to run without failure and, where possible, produce a sensible output.


== optional ==


* "is_transition" : WEED_SEED_BOOLEAN : WEED_TRUE Indicates that this parameter is a transition,
  		    at min the effect is fully "off", showing ONLY the first in_channel as output,
		    at max it is fully "on", showing ONLY the second in_channel as output.
		    Only one parameter may have this leaf, it must be a single valued parameter of type integer or float,
		    and the plugin must have exactlty two mandatory input channels and mandatory output channel.
		    Otherwise this leaf is ignored.
		    Valid only for in parameters.





 * WEED_PARAM_FLOAT

"value" and "default" are constrained by min and max: min <= value <= max

The "default" leaf can only be of seed type WEED_SEED_DOUBLE. "default" may have any number of elements > 0.
0 elements in the default is only allowed for variable sized values, and "new_default" must be defined then.

== mandatory ==
 
 * "min" : WEED_SEED_DOUBLE : minimal value of the parameter, MANDATORY for in parameters (optional for out parameters)

 * "max" : WEED_SEED_DOUBLE : maximal value of the parameter, MANDATORY for in parameters (optional for out parameters)

   Note that although these are mandatory they are still only hints. The host may ignore them and the
   plugin must not assume that data supplied to it is meaningful. If
   the plugin receives invalid input data it is expected to continue
   to run without failure and, where possible, produce a sensible output.

== optional ==

* "is_transition" : WEED_SEED_BOOLEAN : WEED_TRUE Indicates that this parameter is a transition,
  		    at min the effect is fully "off", showing ONLY the first in_channel as output,
		    at max it is fully "on", showing ONLY the second in_channel as output.
		    Only one parameter may have this leaf, it must be a single valued parameter of type integer or float,
		    and the plugin must have exactlty two mandatory input channels and mandatory output channel.
		    Otherwise this leaf is ignored.
		    Valid only for in parameters.




 * WEED_PARAM_TEXT
A string type parameter. The "default" leaf can only be of seed type WEED_SEED_STRING.




 * WEED_PARAM_SWITCH 
Indicates a boolean type parameter. The "default" leaf can only be of seed type WEED_SEED_BOOLEAN.


== optional ==

* "group" : WEED_SEED_INT : for all in_parameters with the same non-zero group: the "default" may only have a
 			    single value, and WEED_PARAMETER_VARIABLE_SIZE may not be set.

			    Only one parameter per non-zero group may have a "default" of WEED_TRUE. 
			    The host should ensure that only one parameter per non-zero group has a "value" of WEED_TRUE. 
			    I.e. this creates a group of "radio" buttons.




 * WEED_PARAM_COLOR

Indicates a colour type parameter. Colors are represented as a list of elements of type WEED_SEED_DOUBLE or WEED_SEED_INT.
Depending on the seed_type of "default" / "new_default", the host knows the seed type of "value".


== Mandatory ==
TODO: fix ambiguities.

* "min" : WEED_SEED_DOUBLE or WEED_SEED_INT; the lower bound for each element, usually 0.
  	  		      		     (optional but recommended for out parameters)
					     A value of {min, min, min, min} indicates black / transparent.

* "max" : WEED_SEED_DOUBLE or WEED_SEED_INT; the upper bound for each element.
  	  		      		     (optional but recommended for out parameters)
					     A value of {max, max, max, max} indicates white / opaque.

* "colorspace" : WEED_SEED_INT : colorspace (see below), MANDATORY


== optional ==

 * "gamma_type" : WEED_SEED_INT : (optional) If the plugin set the flag WEED_FLAG_LINEAR_GAMMA,
   		  		  	     and the host set WEED_HOST_SUPPORTS_LINEAR_GAMMA in the host_info plant.
					     then the values of color parameters are assumed
					     to be scaled using linear gamma.
					     This leaf can be set to WEED_GAMMA_SRGB by the plugin 
					     to indicate that the parameter values are still scaled 
					     the sRGB colourspace. Otherwise it is ignored by the host.


==== Number of elements in the leaves ====


For color parameters:
-- WEED_LEAF_DEFAULT --
The number of elements in "default" set by the plugin MUST be either 3 or 4 (depending on the "colorspace") - 
(3 for RGB, 4 for RGBA).

If the plugin sets the parameter template flag WEED_PARAMETER_VARIABLE_SIZE;
then the "default" may have 0 values, or be absent; and "new_default" MUST contain exactly one RGB(A) value.



-- WEED_LEAF_VALUE --
   This leaf will be of the same seed_type (WEED_SEED_INT or WEED_SEED_DOUBLE) as the 'default" / "new_default" in the template.
   It will have one value of 3 or 4 elements, depending on the colorspace,

- UNLESS the plugin sets the parameter flag WEED_PARAMETER_VARIABLE_SIZE; then the "value" may take any number
  of RGB(A) values, or if WEED_PARAMETER_VALUE_PER_CHANNEL is set then it will conatain one RGB(A) value for each
  non-disabled channel.


-- MIN / MAX --
These leaves may contain 3 or 4 values (depending on the colorspace), or a single value.
In the case of a single value, it applies to all elements (R, G, B (and A)).




== PLANT TYPE FILTER_INSTANCE ==

Plant type filter_instance is created by the host, and used to hold all data that are related to
a single instance of the filter. Mandatory leaves MAY be set IMMUTABLE / UNDELETABLE by the host after weed_setup(),
and should not be altered by the host. 
Optional leaves created by the host MAY be set IMMUTABLE.

The host examines a filter_class and prepares one or more filter_instances from
it. After this the host can pass the filter_instance into the filter's init_func() [if the plugin has one] to prepare to use it.


"type" == WEED_PLANT_FILTER_INSTANCE

'''Mandatory leaves''':[[BR]]

* "filter_class"   : WEED_SEED_PLANTPTR : Pointer to a filter_class plant
 that this filter instance is based on. MUST be one of the filters
 returned in the plugin's plugin_info plant. The host MUST set this when creating the instance, so that the plugin
 can locate the filter that the instance was created for.


The following are MANDATORY if there are corresponding templates in the filter class:

 * "in_channels"    : WEED_SEED_PLANTPTR, list of 0 or more elements : array of in channels, '''type''' of the referenced plants MUST be WEED_PLANT_CHANNEL

* "out_channels"   : WEED_SEED_PLANTPTR, list of 0 or more elements : array of out channels , '''type''' of the referenced plants MUST be WEED_PLANT_CHANNEL

* "in_parameters"  : WEED_SEED_PLANTPTR, list of 0 or more elements : array of in parameters, '''type''' of the referenced plants MUST be WEED_PLANT_PARAMETER

* "out_parameters" : WEED_SEED_PLANTPTR, list of 0 or more elements : array of out parameters, '''type''' of the referenced plants MUST be WEED_PLANT_PARAMETER





The following is optional but recommended, particularly if the plugin set "preferred_fps" for the filter_class.

 * "fps" : WEED_SEED_DOUBLE : the "display" fps of the host running the instance
   (i.e best guess at frequency at which it attempts to call process_func() ).


 * "target_fps" : WEED_SEED_DOUBLE : for plugins which generate video, the rate at which they run internally may differ from
                       the actual display rate. The host may set this leaf to indicate to the plugin the desired frame generation rate
		       (which may be higher than the actual display rate - 
		       In this way, the generation of frames will appear smooth even if the display rate varies.) If this leaf is set
		       then it is MANDATORY for the host to set the "fps" leaf so that the plugin may estimate how many internal
		       frames to generate per display frame. It is recommended that the host set this value BEFORE calling the
		       init_func() for the filter; the value may also be updated by the host between calls to process_func(), however
		       it may not always be possible for a plugin to comply with such changes after the first init_func() has been called.


* "flags" : WEED_SEED_INT : a bitmap of flags informing the plugin it may perform certain updates (see below for definitions)


 * "gui" : WEED_SEED_PLANTPTR : pointer to a plant
           type GUI [see below - GUI plants].
	   The plugin may optionally create and populate one GUI plant for the instance. Teh plant may be updated by the
	   plugin within its init_func() and may be updated by the host prior to calling process_func().


 * Every plugin can store internal data in leaves inside this plant, and host MUST NOT change their values or make them
 READONLY for the plugin. Those internal leaves MUST have keys prefixed with "plugin_".

 * The host may add any additional keys required, but it is recommended that the keys be prefixed with "host_"







== PLANT TYPE CHANNEL ==

Channel plants may be created by the host using channel templates from the filter class as a guide.

Channels MUST be added to a filter instance in the order defined in the channel_templates of the filter_class from which
the instance was generated, with due consideration to WEED_CHANNEL_OPTIONAL and "max_repeats".



After initialisation, channels MUST NOT be added or removed without reinitialising the plugin.

 * "type" == WEED_PLANT_CHANNEL

'''Mandatory leaves for all channel plants''': [[BR]]

* "template" : WEED_SEED_PLANTPTR : Pointer to a channel template plant used to create the channel. The host MUST set this
  	       			  when creating the channel, so that the plugin can locate the channel_template which was used to create
				  this channel. In the case of repeatable channels ("max_repeats" <> 0) there may be several channels
				  pointing to the same channel template.

'''Mandatory leaves for channels with video ''': [[BR]]


* "width" : WEED_SEED_INT    : The frame width in macropixels. Must follow the rules for "width", "maxwidth", "minwidth" and
  	    		       	   	       "hstep" defined for the filter_class, or if the filter_class has the flag
					       WEED_FILTER_CHANNEL_SIZES_MAY_VARY set, 
					       then the equivalent rules from the channel_template if they are present.

 
* "height" : WEED_SEED_INT   : The frame height in pixels. Must follow the rules for "height", "maxheight", "minheight" and
  	    		       	   	       "vstep" defined for the filter_class, or if the filter_class has the flag
					       WEED_FILTER_CHANNEL_SIZES_MAY_VARY set, then the equivalent rules from the channel_template
					       if they are present.

					       If the process_function() is run in threading mode, then for out channels, this leaf will contain
					       two values, the first is the reduced height of the channel for the thread, the second the true height
					       of the channel. (See threading)

* "current_palette" : WEED_SEED_INT: The selected palette, which must be one of the palettes contained in "palette_list"
  		      		     	 	  	   of the filter class used to create the instance to which the channel is attatched,
							   and all channels must have the same value.

							   If the filter_class has the flag WEED_FILTER_PALETTES_MAY_VARY set,
							   then it may be any of the palettes from the channel_template's "palette_list",
							   if that leaf is present, otherwise from the "palette_list" in the filter class.
							   In this case each channel may be set to a different, however each out channel must
							   match the corresponding in_channel, unless the flag WEED_FILTER_IS_CONVERTER is
							   also set.
							   

* "pixel_data" : WEED_SEED_VOIDPTR    : array of n pointers to  the image pixel data. The number of elements depends on
  	       	 		      	      	   	    	"current_palette". The size of each element depends on "rowstrides", "height",
								"current_palette" and the plane number for planar palettes. Host should attempt
								to align each plane according to the "alingment_hint" if that was set for the
								corresponding filter_class. May be cast to / from (uint8_t **).


* "rowstrides" : WEED_SEED_INT     : array of row widths in bytes (include padding / alignment) in "pixel_data". Host should
  	       	 		     	      	  	 attempt to set this to a multiple of "alignment_hint" for the filter_class, if that leaf is
							 present.


'''Mandatory leaves for channels with YUV current_palette ''': [[BR]]


If the plugin sets any of these in the channel_template, and the host is using a YUV
"current_palette", host should try to match plugin preference where
possible, and process video accordingly:

 * "YUV_sampling"     : WEED_SEED_INT : Preferred sampling type for YUV
                                        palettes, host should try to
                                        match if plugin set it in filter_class or template.

 * "YUV_clamping"     : WEED_SEED_INT : Preferred clamping type for YUV
                                        palettes, host should try to
                                        match if plugin set it in filter_class or template.

 * "YUV_subspace"     : WEED_SEED_INT : Preferred YUV Subspace (see below)
                                        type for YUV palettes, host should try to
                                        match if plugin set it in filter_class or template


'''Mandatory leaves for channel plants with audio''': [[BR]]

 See the weed AUDIO extension.

'''Optional leaves for all channel plants''': [[BR]]
 * "disabled"     : WEED_SEED_BOOLEAN : the host may set this to WEED_TRUE before calling init_func()
   		  provided the corresponding channel template has WEED_CHANNEL_OPTIONAL set in its flags,
		  in order to mark non used channels.

		  The Host MUST NOT change this value without reinitialising the instance,
		  UNLESS "max_repeats" is also set for the template, in which case the host may mark any channels
		  created from that template as "disabled" without needing to reinit the filter. However, varying the number
		  (disabled + non-disabled) of channels created from the template still requires a reinit.
		  

 * "flags"        : channel flags set by host.



 * "offset" : WEED_SEED_INT : Will only be used if the plugin sets the filter flag bit WEED_FILTER_HINT_MAY_THREAD.
			      See below - threading.

			      host can achieve multithreading by splitting destination frames into slices, calling the 
   	      		      process_func several times with different offsets and reduced height in the 
			      destination channel. Offset is the number of rows offset of "pixel_data" in the destination 
			      frame(s). 


'''Optional leaves for channel plants with video''': [[BR]]


 * "inner_size" : WEED_SEED_INT[4] : if the host "letterboxes" the image, this leaf may be set.
   The 4 integer values represent (x_offset, y_offset, width, height). Offsets are measured from
   top left, and width and height are in pixels (NOT macropixels). Plugins may use this to cut
   blank borders for example when resizing an image to overlay it.
   If the leaf is absent then no letterboxing has been done.

 * "pixel_aratio"   : WEED_SEED_DOUBLE : physical aspect ratio of the display device that the host is using to display
   			    		       the corresponding out_channel. par = pixel_width / pixel_height.

					       Pixel aspect ratio 
                                               other than 1.0 means pixels are non-square on whatever display device the host is using).
					       For example, if a filter wants to draw an exact circle independant of the display device,
					       then it should take this value into consideration and actually draw an elipse with
					       horizontal radius == vertical_radius / pixel_aspect_ratio.
					       

 * "alpha_premult" :       WEED_SEED_BOOLEAN :
   		  		  	     if the plugin set WEED_FILTER_PREF_PREMULTIPLIED_ALPHA for the filter, then the host MAY
					     set this to WEED_TRUE if the channel contains pre-multiplied data.

					     If not set, then the alpha is post-multiplied.

For RGB type channels:

 * "gamma_type" : WEED_SEED_INT :
   		  		  	     set by the host to indicate the gamma transfer function of the RGB(A)
					     colour space in which the channel operates.
   		  		  	     If not set, it can be assumed to be WEED_GAMMA_SRGB.

					     * If the plugin set the filter flag bit WEED_FILTER_HINT_LINEAR_GAMMA,
					     then the host may set this to WEED_GAMMA_LINEAR to indicate the values are in linear gamma.
					     




'''Optional leaves for channel plants with audio''': [[BR]]

 See the weed AUDIO extension.






== PLANT TYPE PARAMETER ==

Input parameter leaves should only be changed by the host, and
output parameter "value" only by the plugin. Parameters MUST match
one to one with parameter templates (same order, same number).

For output  parameters, the host should create the parameters from their templates, and may set the "value" leaf to the "default".
which plugin provided. The plugin may alter the "value" of any out parameter during its init_func() and during its process_func().

Out parameters are automatically
assumed to have the template flag WEED_PARAMETER_VARIABLE_SIZE set, i.e the plugin may set any number of values in the
"value' leaf (including zero) but the leaf itself should never be deleted.





 * "type" == WEED_PLANT_PARAMETER

'''Mandatory leaves''': [[BR]]

* "template" : WEED_SEED_PLANTPTR : pointer to the parameter_template used to create the parameter. The host should set this
   	      			   so that the plugin can locate any values set in the corresponding template.

 * "value" : seed type of the value MUST match the type of "default"
	     leaf of the parent_template. Lists/arrays can be implemented by
	     setting multiple elements in "default" (fixed list length), 
	     or by setting the parameter flag bit WEED_PARAMETER_VARIABLE_SIZE
	     (variable list length). 

	     For out parameters:
	      this leaf is set by the plugin, first in init_func() (where it MUST be set to its default),
	      then optionally in process_func().


'''Optional leaves''':[[BR]]

 * "gui" : WEED_SEED_PLANTPTR : each parameter (for in_parameters) can have a
    	   		      	     "gui" leaf. This leaf points to a plant of type
 			      	    GUI. Within the GUI plant can be additional leaves to assist the host
 				    to display this particular parameter. The plugin can create it, and
				     set leaf values in it in the init_func()


* Every plugin can have its internal data stored in leaves inside this plant, and host MUST NOT change their values or make them
 READONLY for the plugin. Those internal leaves MUST have keys prefixed with "plugin_".

 * The host may add any additional keys required, but it is recommended that the keys be prefixed with "host_"






== PLANT_TYPE_GUI ==

This plant type has differing properties depending on whether it is
referenced from (i.e. contained in) filter_instance, a parameter_template.or a parameter

These plants are only relevant to hosts that wish to present a graphical interface for controlling a filter,
otherwise all the values may be ignored.



 * "type" == WEED_PLANT_GUI

==== filter_class GUI ====
Plugin may set any of these leaves in weed_setup(). After that the plugin must not alter any leaves, except for private leaves
with keys prefixed "plugin_".


'''Optional leaves''': [[BR]]

 * "layout_scheme" : WEED_SEED_STRING : string defining the layout scheme(s) selected for creating interface windows
					The leaf can take multiple values if the filter provides multiple layout schemes.

					The host may optionally provide a list of schemes which it supports in the
					"layout_schemes" leaf of host_info.

					Depending on the scheme(s) selected, there may
					be further leaves, for example xml, css, and so on.
					These additional leaves should have names starting with "<layout_scheme>_"
					where <layout_scheme> is the name of the layout.

 * "icon"         : WEED_SEED_STRING : name of the associated icon (if
                                       any) in the icons subdirectory [see below - Plugin locations/format]

 * "hidden" : WEED_SEED_BOOLEAN : if set to WEED_TRUE, the filter should be hidden from user menus etc. by the host.
                                     	    	       	   	  (Intended for internal type filters.)

 Example: a plugin creates a special "test" filter which is designed to test some specific feature of a host. The plugin sets
 the leaf "hidden" in the filter_class GUI to indicate that the filter should not be included in general user menus, etc.


 * other optional leaves depend on the "layout_scheme" used by the plugin (if any).



 * Every plugin can have its internal data stored in leaves inside this plant, and host MUST NOT change their values or make them
 READONLY for the plugin. Those internal leaves MUST have keys prefixed with "plugin_".

 * The host may add any additional keys required, but it is recommended that the keys be prefixed with "host_"



==== parameter_template GUI ====

Plugin may set these leaves in weed_setup() At other times neither the plugin must not
alter any of the leaves, except for private keys prefixed "plugin_"  or "host_" respectively.  

All of these leaves indicate optional functionality for the
host. For example, the plugin should not rely on setting "maxchars" to
ensure a string is constrained to certain length, neither should it
rely on setting "copy_value_to" to force the host to set indentical
"values" for two parameters.


'''Optional leaves''': [[BR]]

* "label" : WEED_SEED_STRING : label for display.

 * "use_mnemonic" : WEED_SEED_BOOLEAN : WEED_TRUE indicates that "label" uses
    underscore as a mnemonic accelerator

 * "decimals" : WEED_SEED_INT : number of decimals to be displayed for a FLOAT or
   COLOR (FLOAT) types. For other types this will be ignored.
   This is only a suggestion for display, the actual value may contain more digits after the decimal point.

 * "step_size" : seed type matches type of "default" : step value for
   INTEGER, FLOAT and COLOR type parameters : used for spin buttons, etc. This is only a hint, there is no guarantee that
   the actual value will be an integer multiple of step_size. The interface should "encourage" users to select a value which
   is an integer multiple of "step_size".

 * "maxchars" : WEED_SEED_INT : max display length in (utf-8) chars for a
   TEXT type. For other param types, this will be ignored. A value < 1 should
   also be ignored. This is only a hint for display, there is no guarantee that the actual value will not be greater in length.

 * "wrap" : WEED_SEED_BOOLEAN : only valid for INT and FLOAT types

   	  WEED_TRUE hints to the host that the "value" should wrap when going below min or above max,
   	   I.e attempts to set the value n outside the range of min / max should be resolved by taking the modulus:
	   n mod (max - min + 1) + min,  rather then being clamped in the range min <= n <= max which is the default
	   suggestion.



 * "flags" : WEED_SEED_INT : bitmap of WEED_GUI_* flags. (See below).


///////// (the following leaf may also be set by the plugin in a parameter GUI during init_func())


 * "hidden" : WEED_SEED_BOOLEAN : if set to WEED_TRUE, the parameter is not designed to be displayed by the host  
   when presenting a filter interface to the user (for example, the plugin may create a large number of input parameters
   which are designed to receive data via a data connection and which are not intended to be shown in an interface).
   Setting the value here rather than in the parameter GUI plant indicates a more structural type of setting,
   and thus it may not be overridden in the parameter GUI.

   Example 2: in addition to the normal user interface, a filter has a "reset" parameter which is intended to be connected when
   running in a data processing mode. The plugin sets the value of "hidden" to WEED_TRUE in the parameter template GUI plant,
   to hint to the host that the parameter is not intended for display.




 * "choices" : WEED_SEED_STRING : valid only for in parameters of type WEED_SEED_INT:

 array of strings corresponding to the integers(s) held in the "value" leaf of the parameter. 

 For example this leaf could be used to fill values in a combo box or a pop-up menu.

    If the leaf is present,
    the "max" leaf in the template may be ignored, and "max" may instead be assumed to be equal to the number
    of elements in "choices" - 1.

   when setting up the template, "min" should be set to either 0 or -1. Then:
   for the "value", 0 indicates first element in "choices", and a "value" of -1 indicates "no selection".
   Thus, a "min" of 0 implies that (at least) one value should always be selected, -1 indicates that an empty selection is also
   acceptable.

   If the flag WEED_PARAMETER_VARIABLE_SIZE is set in the parameter template, then multiple entries may be selected.
   (To simplify things, it is recommended that values should be unique and listed in ascending order.)
   
   In this case, there is no requirement to set the "new_default" leaf, as may otherwise be necessary if this flag bit is set,
   since it makes no sense to have a repeated default for such parameters.

   The "default" leaf indicates the default selection(s). This may be -1 (or absent) to indicate a default of "no selection".

   For non-INT parameters, this leaf may be ignored.  If "choices" is present, then "wrap" and "step_size" may be ignored by the host.

   NOTE:
   Occasionally, the plugin may not know the valid set of choices until it is actually initialised, as it may be in a "dormant"
   state until then. In this case, the plugin should do the following:
   - set a 'placeholder' value here so that the host knows the type, and set the flag bit: WEED_GUI_CHOICES_SET_ON_INIT
   in the "flags" for this plant. (See below for more details).

   The plugin is then obliged to create the full list the first time the init_func() is called for the filter. The list should
   be set in a leaf with the same key ("choices") in a GUI plant for the parameter (since updating the parameter template /
   parameter template GUI is prohibited after weed_setup() has returned.)
   The host should take note of this on return from the first init_func() call, and may update any interface elements accordingly.

   Once the values have been set, they may not be altered again until the plugin is unloaded / reloaded and weed_setup()
   called again.

  
 * "choices_langs" :: WEED_SEED_STRING (list) :: an optional list of IETF languages for the host to select from.
   		     		      If present, the plugin should set the flag WEED_GUI_CHOICES_SET_ON_INIT, and the host may optionally
				      set one of the languages from the list in the parameter GUI leaf "choices_lang" before calling the
				      filter init_func() for the first time.



 * Every plugin can have its internal data stored in leaves inside this plant, and host MUST NOT change their values or make them
 READONLY for the plugin. Those internal leaves MUST have keys prefixed with "plugin_".

 * The host may add any additional keys required, but it is recommended that the keys be prefixed with "host_"





==== parameter GUI ====

A Plugin may optionally create and then update a GUI plant for any input parameter during the init_func()

At other times the plugin must not alter any of the leaves, except for any private leaves with keys prefixed "plugin_"

Any parameters which may trigger a change in the GUI when the value changes, (i.e hiding / showing parameters, and setting
copy_value_to) should have the flag bit: WEED_GUI_REINIT_ON_VALUE_CHANGE set in the parameter template GUI when the
plugin is setting up the templates in weed_setup(), (unless WEED_PARAMETER_REINIT_ON_VALUE_CHANGE is set, in which case
it would be redundant).
This is explained in more detail below, along with an explanation of the counterpart to this in the host.




* "copy_value_to" : WEED_SEED_INT : index (0 means first in parameter, 1 means second, etc.)

   if the "value" of this in_parameter is changed, then the "value" of the in_parameter pointed to (by index) should be
   set equivalently by the host. Note that this is only a hint for creating user friendly interfaces. There is no guarantee that
   the host will comply with this hint.

   This functionality can be disabled by the plugin by setting the  value < 0, or by setting it to point to itself.


Example:
an audio plugin (see Weed Audio Extension) operates on two channels, left stereo and right stereo.
The plugin creates two sets of each parameter, one for each channel, and creates a switch parameter "link"
to allow the user to link the parameter values for both audio channels. If link is ON then altering the paramter values for one channel
will also adjust the values for the other one. If link is OFF, then the values can be set independantly.

The plugin achieves this by setting the flag WEED_GUI_REINIT_ON_VALUE_CHANGE in the parameter template GUI for "link".

If a host is displaying a parameter interface for the instance, then it should take note of the flag bit and reinit the plugin
when the value ot the link parameter is altered (e.g by a user checking or unchecking a checkbutton).

Subsequently, during the init_func(), the plugin reads the value of "link", and if set, creates or updates
a GUI leaf for each in parameter, with the "copy_value_to" leaf pointing to the corresponding parameter
for the other audio channel. If "link" is not set then "copy_value_to" is set to -1 to indicate no copying of values.

The host that creates the interface for the plugin will then know to copy the values in the interface, producing the desired result.

Since in this case, the value of the parameter only affects the current interface, the plugin should also set the flag
WEED_PARAMETER_VALUE_IRRELEVANT in the parameter template, so that the host knows not to record / amend the parameter
value changes.



 * "hidden" : WEED_SEED_BOOLEAN : if set to WEED_TRUE, the parameter should be hidden by the host in any interface windows
   	      			This is to allow the plugin to suggest to the host that it show / hide different parameters depending on
				the values of other parameters, channel sizes and palettes, etc. If this leaf also exists in the parameter template
				GUI, then the value of this leaf may be ignored.


 If the plugin wants to update these leaves depending on the value(s) of specific parameter(s),
 then it should set the flag: WEED_GUI_REINIT_ON_VALUE_CHANGE for the parameter templates / GUI  corresponding to the
 parameter(s) whose value change triggers the update.



Example:

the filter has a "mode" parameter which defines various operating modes for that filter. Depending on the value of
"mode", the plugin may want to hint to the host to show or hide some of the other parameters. The plugin achieves this
by setting the flag WEED_GUI_REINIT_ON_VALUE_CHANGE in the parameter template GUI for "mode".

A host which creates a parameter interface for the plugin, observes this flag bit, and thus knows to reinit the plugin
when the value of the "mode" parameter is altered.
During the init_func(), the plugin reads the value of "mode" and sets "hidden" to WEED_TRUE or WEED_FALSE
for several of the other in parameters. On return from init_func(), the host checks the values of "hidden" in any
parameter GUI plants, and may show or hide parameters in the interface accordingly.




 * "choices" : WEED_SEED_STRING :

    As mentioned above -
    Sometimes it is not possible for a plugin to define all the entries in "choices" for a parameter in the weed_setup() function,
    needing to be actually initialised first.

    In this case, the plugin may set this leaf in the PARAMETER GUI plant for the corresponding parameter during its init_func(),
    PROVIDED it set the flag bit WEED_GUI_CHOICES_SET_ON_INIT in the "flags" leaf of the parameter_template GUI.

    The list may be created ONE TIME ONLY, - the first time any instance of the filter class is initialized.
    Once created, the list MAY NOT be altered again untll weed_setup() is called again.

    The plugin should also attempt as much as is feasible to return the same list on every session (i.e maintaining
    the same values, ordering and number of choices to the greatest extent possible).

    On the host side: if a plugin creates a GUI plant in a parameter template of a filter, and sets "choices" in it,
    then, after return from the first init_func() with any instance created for that filter,
    the corresponding parameter should be checked to see if the plugin has set an updated "choices" there.

    The plugin SHOULD set WEED_GUI_CHOICES_SET_ON_INIT in the "flags" of the parameter_template GUI,
    but there may be cases where the rule is neglected.

    Optionally, the host can copy the leaf into the paramter template GUI as if the plugin had set it there originally.

 * "choices_lang" :: WEED_SEED_STRING :: if the plugin set "choices_langs" in the parameter template GUI,
   		    		     then the host may optionally select one of the elements from that list and set it here before calling
				     init_func() for the first time. The plugin may then provide the list of choices in the language
				     selected by the host.



== parameter_instance GUI =====


== Filter Easing ==

THIS IS AN EXPERIMENTAL ADDITION, AND SOME DETAILS MAY CHANGE.

For some filters, it may be visually pleasing for the filter instance to "ease out", rather than being
deinited and switching off right away.

In this case, the plugin may
- CREATE a GUI PLANT for the FILTER_INSTNACE withim the leaf "gui".


- within the instance GUI, there are the folloewing leaves:

"ease_out_frames" : WEED_SEED_INT

this value may be set by the plugin to a number representing the number of processing cycles for the
filter to smoothly return to a "neutral" state, i.e. when this value reaches 0, the output will look indentical
to the input. The value may be updated during each process_func() call.

The value of the leaf is linked to some kind of internal state for the plugin.
The value should be set such that decreasing it by one each cycle causes the plugin to return smoothly no neutral.

e.g it could be a count of previous frames stored in an internal  buffer, and reducing this count by 1 each cycle
would gradually return the output to neutral.


The host can request "easing out" by setting a second leaf in the instance:

"ease_out" : WEED_SEED_INT

If this value is set to non-zero, then for that process_func() call, and each following call, the filter must take 1 step
towards returning the output channel to the neutral state, and additionally it MUST reduce the
value of "ease_out_frames" by 1.

Once "ease_out_frames" reaches zero, the process_func() should simply copy input to output unaltered,
or if it is running 'inplace' then it should do nothing, but just return WEED_SUCCESS.
Output parameters, if any, should be set as they normally would be.



- If "ease_out" is subsequently deleted by the host, or set to 0, then the filter may resume normal operation.
Thus the filter should check for this at the start of its process_func(), and if this is the case then it should
abort the easing process.

In case this is not possible (i.e the plugin has somehow committed to easing out), the plugin should ease down to
zero as normal however it must in this case  return WEED_ERROR_REINIT_NEEDED from each process_func() call.


In case for some reason it is not possible for the filter to continue easing out, then
it should return WEED_ERROR_REINIT_NEEDED.


The value of "ease_out_frames" may be reduced by zero or by more than 1; however this is undesirable behaviour
and should be avoided if at all possible.


Host controlled easing:

In many cases, the plugin filter may be able to return to "neutral" over any number of steps. In this case it may indicate
this to the host by setting "ease_out_frames" to a negative value.

When the host wants to initiate easing out, it can set the value of "ease_out" to an intger greater than zero.
The plugin should aknowledge this by setting "ease_out_frames" to the same value, and then continuing exactly as if the plugin
had set this value itself. (i.e take one step towards neutral, subtract 1 from "ease_out_frames" and so on.)



"ease_in_frames" : WEED_SEED_INT
This value works exactly like "ease_out_frames", except that

- the plugin sets this value in its init_func() for the filter instance.

- if the host wants to use this feature, it will set "ease_in_frames" to non-zero prior to the FIRST process_func() after calling
init_func().

- the plugin may then begin decreasing its "ease_in_frames" on each process cycle.
when the value reaches zero, the plugin is operating at "full strength".

The same rules apply for the host setting "ease_in" to zero - in this case the filter should immediately go to full strength,
and if not possible then return WEED_ERROR_REINIT_NEEDED.




=== WEED_SETUP ===========

The full details of the plugin / host initialisation are described here.

The host should first load the plugin and then at some later point mat call the weed_setup() function in it.


e.g:

....
weed_setup_f setup_fn = (weed_setup_f)dlsym(handle, "weed_setup");

weed_plant_t *plugin_info = (*setup_fn)(weed_bootstrap); // using weed_bootstrap from libweed-utils



At the start of weed_setup(), the plugin must call the weed_bootstrap function, passing in a pointer to receive default_getter_f,
and the lowest and highest versions of WEED_API_VERSION and WEED_FILTER_API_VERSION it supports, the returned value will be a
host_info plant created by the host, e.g.:


  weed_default_getter_f weed_default_getf;
  weed_plant_t *host_info = (*weed_boot)(&weed_default_getf, weed_api_min_version, weed_api_max_version,
                                         weed_filter_api_min_version, weed_filter_api_max_version);




Control now returns to the host in its weed_bootstrap function.


weed_plant_t *weed_bootstrap(weed_default_getter_f *value,
			     int32_t plugin_min_weed_api_version,
			     int32_t plugin_max_weed_api_version,
			     int32_t plugin_min_filter_api_version,
			     int32_t plugin_max_filter_api_version);



The host now has a chance to review which weed and filter api versions the plugin supports and to adjust the functionality
offered to the plugin accordingly. It is for this reason that the host does not pass the host_info plant directly to the plugin
when calling weed_setup.

If the host does not support the plugin's api versions, it should return NULL from weed_bootstrap.
In this case the plugin should return NULL from the weed_setup() function, so that the host can unload it.


Otherwise, the host will set value to point to a default getter function in the host of the form:

{{{
   weed_error_t default_getter(weed_plant_t *plant, const char *key, void *value)
}}}

and return a configured HOST_INFO plant.

value should be a pointer to a variable suitable for the value requested. The plugin (or library) should first fetch the Weed API
version (key = WEED_LEAF_WEED_API_VERSION or WEED_LEAF_WEED_ABI_VERSION, type = int32_t)
then depending on the value of that it can retrieve the core Weed functions for the API version, or return NULL if it's an
unsupported version.

After this, the plugin or library  may retrieve the filter API version (key = WEED_LEAF_FILTER_API_VERSION, seed_type =
WEED_SEED_INT, using the normal Weed functions, and either choose to continue or else return NULL.




If using libweed-utils, the provided weed_bootstrap will automatically check versions and set the plugin API accordingly.
Its weed_bootstrap also provides a callback to the host so that the host can adjust the configured host_info.


example:

  if ((*weed_default_getp)(host_info, WEED_LEAF_GET_FUNC, (weed_funcptr_t *)&weed_leaf_get) != WEED_SUCCESS) return NULL;


[The default getter should use only standard memory functions, so that the plugin can 
bootstrap its memory functions (weed_malloc, weed_free, weed_memcpy etc.).
There is a version implemented in the weed_utils library which the host can use.]


Normally a plugin would use a utility library which would take care of
calling the bootstrap function and setting up its API functions.

The plugin can also retrieve the "weed_api_version" and "filter_api_version" leaves to discover the API versions the host
assigned it. 

The weed_setup() function in the plugin will return a PLUGIN_INFO plant that
specifies what is the content of this plugin - which filter classes it has, who is the maintainer, etc.

The Plugin implements weed_setup() in following way: the PLUGIN INFO plant is first created by using weed_plant_new(). 
The individual filters are then created and added to the "filters" leaf in the PLUGIN INFO plant.
If no filters can be created (because of memory or other problems or version mismatches), the function should return NULL.

The returned plant MUST have '''type''' WEED_PLANT_PLUGIN_INFO.



To recap:

1) host calls weed_init() once with an API version to get its weed functions

2) host dlopens a plugin, then calls weed_setup() in the plugin, passing in a ponter to the bootstrap_fn

3) plugin calls the bootstrap_fn in the host, passing ptr to default_getter, and and min and max api versions it can support.
   The maximum versions should be set to the current version at the time the plugin is created.
   If the plugin is later updated, the max versions can be increased accordingly.

4) host selects weed and filter api versions it will provide, ensuring these are higher than the
   lowest version that the plugin supports (because it cannot know what features may be added in the future...),
   and if higher than the maximum, that the versions are compatible.
   It also sets default_getter function for plugin.
   If the host cannot support the API versions of the plugin, then it should return NULL.

   The idea is that if a plugin relies on features that the host cannot support yet, then it should not be loaded.
   In addition, if a future change breaks compatibility with the plugin, then the host has the option of using a lower API
   version so that the plugin can still run.

   Thus, it is advisable for a plugin author to set the minimum values as low as possible, and the maximum values to the current
   versions. If features were added between the highest and lowest versions, then the plugin can check the host API versions to
   discover whether or not the host supports them.

   The maximum values should be set manually and should not be set from the WEED_API_VERSION or FILTER_API_VERSION symbols,
   as these may increase each time the plugin is compiled. It may be that a future API version breaks compatibility and
   the host will assume that the plugin can handle the changes.



5) after returning from weed_bootstrap, the plugin should check the API version returned by the host,
   and use the default_getter function to bootstrap itself and then fetch the appropriate functions for that API version.




6) plugin then sets up its plugin_info plant and returns it as the value from weed_setup()



This may seem complex, but it provides several advantages:

- each API version can have its own set of core functions

- host and plugin can negotiate the plugin API version and select the highest version which they both 
  support

- function overloading can be done. The host and plugin can have functions with the same name
  but which actually resolve to different functions (for example, host and plugin both use
  weed_leaf_set, but the the host can set this to point to a different version of the function, for example to debug a particular
  plugin.

- the host can have access to functions which the plugin cannot, for example, only the host 
  can call weed_leaf_delete, (unlocked) weed_plant_free and weed_leaf_set_flags






== WEED FLAGS AND TYPES ==


==== Plant types ====

  * WEED_PLANT_HOST_INFO

  * WEED_PLANT_PLUGIN_INFO

  * WEED_PLANT_FILTER_CLASS

  * WEED_PLANT_FILTER_INSTANCE

  * WEED_PLANT_CHANNEL_TEMPLATE

  * WEED_PLANT_PARAMETER_TEMPLATE

  * WEED_PLANT_CHANNEL

  * WEED_PLANT_PARAMETER

  * WEED_PLANT_GUI


==== Filter errors ====

Defined in weed-effects.h

 *  WEED_SUCCESS
    (This is a standard Weed error code defined in weed.h)
    The plugin should return this if it encountered no errors in the function. a.k.a WEED_NO_ERROR.

 *  WEED_ERROR_PLUGIN_INVALID    (Any plugin function)   [severity = FATAL]
    May be returned from any plugin function.
    The plugin encountered a fatal error and should no longer be used. The host should call deinit_func() for any active instances
    and then the desetup function for the plugin, and refrain from using it further.

 *  WEED_ERROR_FILTER_INVALID    (init_func() or process_func())    [severity = CRITICAL]
    May be returned from init_func() or process_func(). Only applies to plugins which create multiple filters (e.g. wrapper
    plugins.) The filter_class from which this instance was created from is no longer valid.
    The host should call deinit_func() for any active instances created from the corresponding filter class, and refrain from
    using them further. The host may still use other, valid filters in the plugin.

 *  WEED_ERROR_TOO_MANY_INSTANCES   (init_func() only)   [severity = MAJOR]        
    If a plugin allows only a limited number of filter instances, it may return this from the init_func().
    The host must not call any further plugin functions for the instance.

*   WEED_ERROR_MEMORY_ALLOCATION    (init_func() or process_func())   [severity = MAJOR]
    (This is a standard Weed error code defined in weed.h)
    The plugin may return this from the init_func() or process_func(). The plugin iself should call deinit_func() on the instance
    and free any internal memory structures. The host must not call process_func() or deinit_func() for the instance,
    but may retry the init_func() with the same or a new instance.

 *  WEED_ERROR_REINIT_NEEDED     (process_func() only)     			[severity = MINOR]
    Returned from process_func(). The plugin enountered an error condition and requires that the host call deinit_func() and
    init_func() again before retrying the process_func(). If the plugin returns this error again after reiniting by the host,
    then there is a fault either in the plugin or in the host.
    This should only be used for emergency situations; generally the channel_template or parameter_template flags should be
    sufficient to correctly define the host / plugin interface.

 *  WEED_ERROR_NOT_READY     (init_func() or process_func())   		[severity = MINOR]
    The plugin may return this error from process_func() if it was temporarily unable to process the data / produce output.
    For example ihe host may be playing too fast or the filter may be still initializing / buffering data.
    It is up to the host how to handle this error; for example it could repeat the last data, if it still has it, show a blank frame,
    or wait and call the process_func again.
    The plugin may also return this from the init_func() in the case that for some reason the filter is not
    ready; perhaps the plugin has just been loaded or deinited and it is waiting for some hardware to become ready.
    In this case the host need not call the deinit_func(), but may retry the init_func() at a later time. The host should not call
    process_func() until it has received WEED_SUCCESS from the init_func.


==== host plugin flags ====

 * WEED_HOST_SUPPORTS_LINEAR_GAMMA  
   Denotes that the host will pay attention to the WEED_FILTER_HINT_LINEAR_GAMMA filter flag.

 * WEED_HOST_SUPPORTS_PREMULTIPLIED_ALPHA
   Denotes that the host will pay attention to the WEED_FILTER_HINT_PREMULTIPLIED_ALPHA filter flag.



== Verbosity levels =====

The host may optionally set this in the host_info plant, using one of the defined values below.

WEED_VERBOSITY_SILENT 	(-2) : no info / error / debug output whatsoever.

WEED_VERBOSITY_CRITICAL 	(-1) : show only errors which prevent a filter / plugin from operating at all 

WEED_VERBOSITY_ERROR 	(0) : WEED_VERBOSITY_CRITICAL + errors which prevent the plugin from operating "normally"

WEED_VERBOSITY_WARN 	(1) : WEED_VERBOSITY_ERROR + errors which the plugin may compensate for, but may
		       	 		      	adversly affect its operation.

WEED_VERBOSITY_INFO 		(2) : WEED_VERBOSITY_WARN + any general informational messges

WEED_VERBOSITY_DEBUG 	(3) : WEED_VERBOSITY_INFO + debugging messages





==== Filter_class flags ====

 *  WEED_FILTER_NON_REALTIME    [[BR]]
    non-realtime filter: the filter is too slow to use in realtime processing.
    The exact definition of what is realtime and what is not is left to the plugin author to decide.

 * WEED_FILTER_HINT_STATELESS    [[BR]]
   This is optional, if the filter is stateless (i.e. not dependant on
   past calls to process_func() ) then this this flag
   bit can be set. Used mainly for compatibility with other plugin architectures.

 * WEED_FILTER_PREF_LINEAR_GAMMA
   This is a hint to the host that the plugin prefers to use R, G, B values in linear gamma space.
   (see note below about colour spaces). Hosts which support this option should set the flag bit
   WEED_HOST_SUPPORTS_LINEAR_GAMMA in the host_info plant.

 * WEED_FILTER_PREF_PREMULTIPLIED_ALPHA
   This is a hint to the host that the plugin prefers to receive pre-multiplied alpha (i.e the values of the color pixels should
   already be multiplied by the alpha value). Hosts which support this option should set the flag bit
   WEED_HOST_SUPPORTS_PREMULTIPLIED_ALPHA in the host_info plant.

 * WEED_FILTER_HINT_PROCESS_LAST
   This is a hint to the host that the filter should be run AFTER all other filters have performed their processing.
   Examples might be a video filter that overlays subtitles on the finished frame, or performs letterboxing,
   or an audio filter that mixes the final output of several input audio channels or overlays a commentary.
   If there are multiple filters like this in
   the processing chain, then the host (or the user) may decide the order to run them in. However, the set of filters which set this flag
   bit should be run as a whole after any filters without this flag have completed their processing for the cycle.

*  WEED_FILTER_HINT_MAY_THREAD
   If a video plugin (TODO - implement for audio ) operates in such a manner that its output may be subdivided vertically,
   then it may set this hint. Ignored for filters which have no out_channels.
   See note below about threading.


 * WEED_FILTER_HINT_MAYBE_UNSTABLE
 The plugin may set this flag bit to indicate that the particular filter may be "problematic". For example, a wrapper type plugin may
 set this flag bit to indicate that the filter in question has deviated from the wrapped type specification - perhaps failing to set valid
 default values for parameters; or for filters that exhibit 'buggy' behaviour such as memory leaks or occasional crashes. It is left to
 the host application to decide how to handle this - it may choose to ignore such filters, run them in a 'sandbox'; or perhaps
 alert the user if the filter is selected for use.

The flag bit may also be applied in the case where a flaw is discovered in a filter and resolving it requires a version update;
 - in this case the flag bit may be set for the older version so that the host application may take appropriate measures
  such as encouraging the user to migrate to the newer version


*  WEED_FILTER_IS_CONVERTER   [[BR]]
    see below

 *  WEED_FILTER_CHANNEL_SIZES_MAY_VARY    [[BR]]
    see below (video filters only)

 *  WEED_FILTER_CHANNEL_PALETTES_MAY_VARY    [[BR]]
    see below (video filters only)


Explanation of flag bit combinations:

    In Weed, all video channels are assumed to have the same (macro) pixel size (width and height - but not necessarily rowstrides)
    as the first non-disabled in_channel (or first non-disabled out_channel for filters that have no in channels).
    All video channels are also assumed to have the same "current_palette" as the first non-disabled in_channel
    (or first non-disabled out_channel for filters that have no in channels).
    The flag bits: WEED_FILTER_CHANNEL_SIZES_MAY_VARY and WEED_FILTER_CHANNEL_PALETTES_MAY_VARY override this
    behaviour, in conjunction with the flag bit WEED_FILTER_IS_CONVERTER.

    WEED_FILTER_IS_CONVERTER on its own has no meaning However it may be combined with either or both of the other flag bits.

    If the flag bit WEED_FILTER_CHANNEL_SIZES_MAY_VARY is set, then each channel may have a different size
    (and / or rowstrides value).

    If the filter has 0 output video channels, then the filter is assumed to be some kind of analyser (i.e. it would normally
    have out_parameters).

    If the filter has one or more output channels then it is assumed to be some kind of compositor.

    If the flag bit WEED_FILTER_IS_CONVERTER is also set then the filter is a resizer filter. In this case its sole function
    should be to reproduce the
    input at the selected out size(s). It MUST have exactly 1 input but may have 1 or more output channels.

    The exact resizing method is left to the filter to decide (for example it may offer
    a border - or letterboxing, or scale at selectable quality values).




    If the flag bit WEED_FILTER_PALETTES_MAY_VARY is set, then each of the input channels may have ANY of the palettes
    declared in the filter class, or in the corresponding channel_template's "palette_list" (whih may be used to override the filter class
    defaults).

    The number of out video channels must be either 0, 1, or equal to the number of input video channels,

    If the filter has 0 output video channels, then the filter is assumed to be some kind of analyser, and no further consideration of
    palette matching is necessary.

    If the filter has 1 in and 1 out channel, then it must also set the flag WEED_FILTER_IS_CONVERTER (See below) and it MUST convert
    between in and out palettes, UNLESS it is simply changing palettes around without any conversion of values, (e.g. RGB24 <-> BGR24,
    RGB24 <-> RGBA32 , YUV888 <-> YUV444P); in this case WEED_FILTER_IS_CONVERTER should not be set.

    If the filter has multiple input channels and a single ouptut video channel, then it can be assumed that the filter combines the
    input channels in some way (for example a filter which mixes two colour channels using a separate alpha layer (alpha mixer),
    could define three in channels:
    two with colour palettes (perhaps using the filter class defaults) and a third (possibly optional)
    with only alpha palettes in the channel template "palette_list"),
    or for example 3 or 4 input channels with WEED_PALETTE_ALPHA8 could produce an output RGB, RGBA or YUV (unclamped) palette.

    IF a filter has 1 in and multiple outs then it is a splitter, for example it could take RGBA32 in and produce RGB and alpha as output.
    or it could split RGB24 to 3 alpha channels (R, G, and B for example).


    If the filter has multiple ins and outs, then
    if an input channel is marked optional then the corresponding output channel is assumed to be optional.
    and if an in channel has "max_repeats" then the corresponding out channel is assumed to have the same value (though it is good
    practice to mark these options specifically (i.e if there is more than 1 output channel, then it must be possible to match it with a 
    corresponding in_channel to match the palettes for that pair).
    The palettes of each output channel are assumed to equal to that of the corresponding (by numeration) input channel.
    I.e. the filter need never change palettes between input and output - UNLESS:


    If the flag bit WEED_FILTER_IS_CONVERTER is also set, then the filter is a palette converter and In this case its sole function
    should be to convert from the palette of each input channel to the palette of the corresponding out channel, or in the
    case of single input channel, to duplicate the input in each of the selected output channel palettes, or in the case of multiple
    inputs and single output, to combine the inputs in some fashion (e.g adding an alpha layer). If the flag bit is set then conversion
    of channel values will be done, e.g. converting RGB <-> YUV.
    

    The "palette_list"s of the input and output channels define the palettes that can be accepted / will be produced.



    The flag bits WEED_FILTER_CHANNEL_SIZES_MAY_VARY and WEED_FILTER_PALETTES_MAY_VARY may be combined, with or without
    WEED_FILTER_IS_CONVERTER.

    These flags may also be combined with any of the other flags.

    Note that for audio filters, the meaning of the flags WEED_FILTER_IS_CONVERTER and WEED_FILTER_CHANNEL_SIZES_MAY_VARY
    is somewhat different than for video filters (see Weed Audio Extension).


=== filter instance flags ===

* WEED_INSTANCE_UPDATE_GUI_ONLY 1
  This filter instance flag bit may be set by the host as a counterpart to the filter setting WEED_GUI_REINIT_ON_VALUE_CHANGE in
  the GUI plant of a parameter_template. This indicates to the plugin that it is being reinited solely in response to a value change in
  the corresponding parameter, and the filter should ONLY update the GUI plants for parameters without disturbing the runniing state
  (e.g nothing should be freed in the deinit_func(), nothing should be reset in the init func()). The host should still call the deinit_func()
  before (re) calling the init_func() in case the filter does not check for this value. This is optional for the host to set, if not set
  then the filter should reinit as normal. A filter which sets the GUI flag WEED_GUI_REINIT_ON_VALUE change in one or more
  parameter template GUIs should check for this value in the "flags" of the instance in its init and deinit functions.



==== Channel template flags ====

  * WEED_CHANNEL_OPTIONAL
    channel that can be disabled during processing.
    The host MUST still create the channel, however if the "disabled" lef is set to WEED_TRUE for the channel, all the other
    leaves in it should be ignored.
    The host must reinit the instance if a channel is enabled or disabled after init_func().
    The exception to this rule is for channel templates which have "max_repeats" set. In that case the host may create up to
    n copies of the channel from the template (if n is 0, then a limitless number). If such a channel is also set optional, then
    the host may choose to make zero copies of it. In addition, the host may enable / disable channels created from such
    a template without the need for a reinit, provided the number of copies rmains the same.

 *  WEED_CHANNEL_CAN_DO_INPLACE    [[BR]]
    The flag bit is only valid for OUT channels.
    If this flag bit is set, the filter can do inplace operations (source and destination are the same)
    Hosts can select this mode by setting all of the leaves of the out channel including the "pixel_data",
    to the same values as the corresponding (same index) in channel.
    TODO: clarify how "disabled" / repeating channels should be handled.

*  WEED_CHANNEL_REINIT_ON_SIZE_CHANGE   [[BR]]
    host must reinit the filter before calling process_func() if the
    channel size (height or width in pixels - NOT MACROPIXELS) is changed.
    For example, WEED_PALETTE_UYVY has a "width" measured in
    macropixels (4 bytes), but each macropixel contains 2 RGB pixels. So if the palette were to change from RGB24 to UYVY,
    the "width" would be halved, however the filter would not be reinited, since the "width" in pixels has not changed.
    If this is likely to cause problems, then set either WEED_CHANNEL_REINIT_ON_ROWSTRIDES_CHANGE
    or WEED_CHANNEL_REINIT_ON_PALETTE_CHANGE in addition.

 *  WEED_CHANNEL_REINIT_ON_PALETTE_CHANGE   [[BR]]
    host must reinit the filter before calling process_func() if the channel palette is changed. For YUV palettes,
    the host must also reinit the filter if the clamping, subspace or sampling changes.

 *  WEED_CHANNEL_REINIT_ON_ROWSTRIDES_CHANGE    [[BR]]
    host must reinit the filter before calling process_func() if the
    any of the rowstrides are changed. Note that	 
    changing the palette can sometimes affect the rowstrides.

    Explanation:
    For example, if the input palette were to change from RGB to RGBA, then
    even though the width in pixels might be the same, the rowstrides value will change (e.g from
    3 * width to 4 * width. So if a filter is sensitive to frame size changes it may want to set
    WEED_CHANNEL_REINIT_ON_ROWSTRIDES_CHANGE. rather than WEED_CHANNEL_REINIT_ON_SIZE_CHANGE.
    Also, some palettes have macropixels with mote than one pixel.

    On the other hand, some filters may not care about the rowstrides value (e.g. they store 1 byte per actual pixel)
    in which case they should set WEED_CHANNEL_REINIT_ON_SIZE_CHANGE.

    The plugin should set the appropriate flag bits to minimise the number of reinits.

 * WEED_CHANNEL_NEEDS_NATURAL_SIZE
   If this flagbit is set, the host should add an extra leaf to channels created from this template: "natural_size".
   This is intended for filters which use fixed size objects (e.g. text);
   the object should be scaled proportionally using the ratio  actual channel size / natural size.
   (In simple terms, if the image has been stretched, then the fixed size object should be stretched accordingly).

   In order to function properly, the plugin should look at the "inner_size" leaf set by the host and
   use the letterboxed width and height as the "actual size".

   Natural size is not restricted by the usual channel rules (maxwidth, maxheight, minwidth, minheight, hstep, vstep,
   alignment_height), since these apply only to the scaled channel size.

   In addition, if WEED_CHANNEL_REINIT_ON_SIZE_CHANGE is also set, the host need only reinit the filter when the
   "natural_size" changes. WEED_CHANNEL_REINIT_ON_ROWSTRIDES_CHANGE is not affected, however.

   Only valid for in_channels.



Flag bits >= 30 are free to use for custom flags.




==== Parameter template flags ====

 * WEED_PARAMETER_REINIT_ON_VALUE_CHANGE
   host must reinit the filter if the parameter "value" is
   changed. This is to allow the filter to readjust its internal state depending on some paramter value (e.g a 'mode'
   setting). It is strongly recommended to set this flag bit only for parameters of type SWITCH, or INT.
 

 * WEED_PARAMETER_VARIABLE_SIZE

   plugin can set this to inform the host that the number of values in the parameter "value" leaf can vary.
   If not set, then the number of values in "value" is fixed; it must always match the number of values in "default".

   If this is set, then the filter may only use one element in each of "min" and "max" for the parameter,
   (except for COLOR parameters which may use 3 or 4 depending on the "colorspace".)

   Note also that 0 is a valid number of elements. [0 elements means the leaf exists but has no value]

   If this is set for an in parameter, the filter MUST also set the "new_default" leaf for the parameter.

   This flag is ASSUMED for out parameters.


 * WEED_PARAMETER_VALUE_PER_CHANNEL
   This flag bit indicates that each element (or set of 3 or 4 elements in the case of color parameters)
   in the parameter "value" corresponds to one input channel. The mapping of values to channels includes channels created from
   repeating templates which may be temporarily disabled, but does not included optional, non repeating channels
   which are disabled. In other words: the number of values / channels is fixed when the host calls the init_func in the filter,
   and may only be altered by reinitializing the filter.

The order of channels and values is the same.

   N.B:
   If a channel template has "max_repeats" set to other than 1, then WEED_PARAMETER_VARIABLE_SIZE
   is ASSUMED to be set for the parameter, as it must shrink and grow depending on the number of channels created.

   This in turn means that the "new_default" leaf should also be set.
   It is highly recommended to set the flag bit anyway to make things easier for the host application.

   (Valid for in parameters only)


 * WEED_PARAMETER_VALUE_IRRELEVANT :: setting this bit informs the host that the "value" of the parameter should be ignored
  when storing / restoring the state of an instance, it should only be intialized with its default value and not changed.
  Examples might be: a parameter whose value is only used for updating the
  GUI (see below); in this case the filter may set the GUI flag WEED_GUI_REINIT_ON_VALUE_CHANGE as well as this flag bit;
  and the value is only relevant when displaying an interactive GUI.
  or a filter could have a "reset" switch parameter with WEED_PARAMETER_REINIT_ON_VALUE_CHANGE, but which is only
  intended for debugging purposes - in this case the host should reinit the instance, but the parameter change should not be
  recorded.

  in addition a filter may set this in the case that a newer version of the filter exists, and this parameter no longer has any
  functional value. Consider also setting "hidden" to WEED_TRUE in the parameter template GUI plant.

  In the case of out parameters, setting the flag bit indicates that the filter will never update the parameter "value".


Flag bits >= 30 are free to use for custom flags.





=== GUI plant flags ====
(only valid for parameter_template GUI)

* WEED_GUI_CHOICES_SET_ON_INIT :: indicates to the host that the list of strings in "choices" set in the parameter_template GUI
  			      	 	      	       	    during weed_setup()
							    is a placeholder only, and that the real list should be read from the parameter GUI 
							    after the first init_func() is called for an instance of the filter_class.



* WEED_GUI_REINIT_ON_VALUE_CHANGE :: hints to the host that if the "value" of the parameter created from the
  				     	       	      	   	   parameter_template is updated, then the filter should be reinited,
								   and on return from init_func,
								   the values of "hidden" and "copy_value_to" for any parameter GUI plants
								   should be (re)checked. If the host is not currently displaying a visual interface for
								   the filter parameters then this flag bit may be ignored.; however,

								   This flag bit MUST be set for any parameter for which may result in a GUI change
								   when its value is altered.

								   In the case that the filter sets WEED_PARAMETER_REINIT_ON_VALUE_CHANGE,
								   in the parameter template flags, this flag bit MUST still be set to indicate that the
								   value change may ADDITIONALLY cause changes in the parameter GUI plants.

								   This flag may be combined with the parameter template flag bit
								   WEED_PARAMETER_VALUE_IRRELEVANT. In this case, the ONLY effect of changing
								   the value MUST BE to update the parameter GUI plants, and thus the host should not
								   record / restore the value changes to this parameter.




								   IMPORTANT:
								   Before calling deinit_func() / init_func() for a filter instance, the host MAY set the flag bit
								   WEED_INSTANCE_UPDATE_GUI_ONLY in the "flags"
								   leaf of the filter instance, to request that the filter ONLY update the parameter GUI plants
								   during the deinit_func() / init_func.

								   The host may do so IF AND ONLY IF the sole reason for reiniting
								   the filter is to update the GUI - i.e a change is made to one or more parameters which
								   have WEED_GUI_REINIT_ON_VALUE_CHANGE set, and none of the changed parameters
								   have WEED_PARAMETER_REINIT_ON_VALUE_CHANGE set. The plugin should still check
								   anyway in case a WEED_PARAMETER_REINIT_ON_VALUE_CHANGE param was altered
								   and the host overlooked this. In the latter case the filter should still only update the GUI,
								   and should then return WEED_ERROR_NEEDS_REINIT to alert the host.
								   
								   
								   To recap:
								   Setting this flag bit does not affect setting WEED_PARAMETER_REINIT_ON_VALUE_CHANGE
								   in the parameter template. If altering the value of the parameter affects both
								   the functional and the display status of the filter instance, then both flags must be set.

								   This differs from the template flag WEED_PARAMETER_REINIT_ON_VALUE_CHANGE in
								   that this flag is only a hint to reinit the instance if the host is showing a real time interface
								   with the current parameter values, or that the filter MAY update the GUI plants IN
								   ADDITION to updating the state in the case that
								   WEED_PARAMETER_REINIT_ON_VALUE_CHANGE is also set in the template.




==== Weed parameter types ====

 * WEED_PARAM_UNSPECIFIED  0
   Parameter is of an unknown type. Plugins should never use this
   by choice, it is intended for wrapper plugins which may need to
   enumerate out of scope parameter types. These parameter types may or may not
   have "min" and "max". They should have at least "name", and if possible "default" leaves, even if the seed_type is only set.

 * WEED_PARAM_INTEGER  1

 * WEED_PARAM_FLOAT  2

 * WEED_PARAM_TEXT  3

 * WEED_PARAM_SWITCH  4

 * WEED_PARAM_COLOR  5

Parameter types >= 1024 are reserved for custom parameter types.



==== Weed colorspaces ====
 // Used for WEED_PARAM_COLOR parameters.

 * WEED_COLORSPACE_RGB  1

 * WEED_COLORSPACE_RGBA  2

Colorspaces >= 1024 are reserved for custom color spaces.







==== Weed palette types ====

Some palettes have aliases; these are shown on the same line.

For packed palettes, the ordering of the colors is as indicated by the name, regardless of the endianness of the host system.

E.g for RGBA32, the first byte is red, the second green, the third blue, and the fourth alpha:

Rmask = 0xFF000000, Gmask = 0x00FF0000, Bmask = 0x0000FF00, Amask = 0X000000FF

Palettes are assumed to be composed of uint8_t color values, unless otherwise specified.




'''Special Palettes'''
Palette number 0
WEED_PALETTE_NONE	a.k.a	WEED_PALETTE_END

Special value used to indicate no palette, unknown / undefined palette, or to mark the end of a list of palettes.

[note: some of these values changed or were corrected as of API version 200. The current values are now fixed and will not
be altered in future versions, the only exception being adding new aliases or removing incorrect ones.]

'''RGB Palettes'''
Palette numbers >0 and <512
{{{
WEED_PALETTE_RGB888         WEED_PALETTE_RGB24   1  :: packed, 8 bits per colour channel, 24 bits per pixel, RGB
WEED_PALETTE_BGR888         WEED_PALETTE_BGR24   2  :: packed, 8 bits per colour channel, 24 bits per pixel, BGR
WEED_PALETTE_RGBA8888       WEED_PALETTE_RGBA32  3  :: packed, 8 bits per colour channel, 32 bits per pixel, RGBA
WEED_PALETTE_BGRA8888       WEED_PALETTE_BGRA32  4  :: packed, 8 bits per colour channel, 32 bits per pixel, BGRA
WEED_PALETTE_ARGB8888       WEED_PALETTE_ARGB32  5  :: packed, 8 bits per colour channel, 32 bits per pixel, ARGB
WEED_PALETTE_RGBFLOAT                            64  :: packed, 32 bit float per channel RGB (range is 0. to 1.)
WEED_PALETTE_RGBAFLOAT                           65  :: packed, 32 bit float per channel RGBA (range is 0. to 1.)

}}}
'''YUV Palettes'''
Palette numbers >=512 and <1024

Ranges are 16-235 for Y, 16 - 240 for U and V, unless
WEED_YUV_CLAMPING_UNCLAMPED is set in "YUV_clamping" for
channel/channel_template (in which case the range is 0 - 255 for each component).

Subspace may be any predefined YUV subspace, unless "YUV_subspace" is set for channel/channel_template.



{{{
WEED_PALETTE_YUV420P           WEED_PALETTE_I420       WEED_PALETTE_IYUV    512
[8 bit Y plane followed by 8 bit 2x2 subsampled U and V planes. Planar.
 The sampling locations of the U and V values relative to the Y values may vary (aligned with Y or between Y)
(Official name YV12)]


WEED_PALETTE_YVU420P           WEED_PALETTE_YV12        				   513
[Same as YUV420P , but the ordering of the U and V planes is reversed in the pixel_data. Planar.
 The sampling locations of the U and V values relative to the Y values may vary (aligned with Y or between Y)
      (Official name IYUV)]


WEED_PALETTE_YUV422P           WEED_PALETTE_P422				    522
[Official name 'YV16', 8 bit Y plane plus two horizontally subsampled U and V planes. The sampling locations of the U and V values
relative to the Y values may vary
Planar.]


WEED_PALETTE_YUV444P   544
[unofficial. 8 bit Y plane followed by 8 bit U and V planes, no
   subsampling. Planar version of YUV888]


WEED_PALETTE_YUVA4444P   545
[Unofficial, like YUV444P but with an additional Alpha plane. Planar version of YUVA8888]


WEED_PALETTE_UYVY         WEED_PALETTE_UYVY8888     WEED_PALETTE_Y422    WEED_PALETTE_UYVY422
			  			    WEED_PALETTE_HDYC 564
[YUV 4:2:2 (Y sample at every pixel, U and V sampled at alternate
   pixels horizontally on each line). A macropixel of 4 bytes expands to 2 pixels when converted to RGB.
Uses same bandwith as YUV422P
The sampling locations of the U and V values relative to the Y values may vary
   Packed. If the "YUV_subspace" is set to bt709, this becomes HDYC.]

WEED_PALETTE_YUYV         WEED_PALETTE_YUYV8888          WEED_PALETTE_YUY2      WEED_PALETTE_YUYV422    565
[Like UYVY but with different component ordering within the macropixel. Packed. Also known as YUY2]


WEED_PALETTE_YUV888                   WEED_PALETTE_IYU2      588

Packed YUV palette, no subsampling. Also known as IYU2


WEED_PALETTE_YUVA8888                                        589
Packed YUV palette YUV888 with an alpha channel. No subsampling.


WEED_PALETTE_YUV411                   WEED_PALETTE_IYU1           WEED_PALETTE_UYYVYY411                    595
[IEEE 1394 Digital Camera 1.04 spec. Is packed YUV format with a 6 byte macropixel structure which converts to 4 RGB pixels.
Ordering in the macropixel is U2 Y0 Y1 V2 Y2 Y3. Uses same bandwith as YUV420P
Used for SMPTE DV NTSC / DVCPRO PAL (???)]
Also known as IYU1.


'''Alpha Palettes'''
Palette numbers >=1024 and <2048

Alpha palettes are generally used as mask/transparency channels but may be used to store any position dependant data.

{{{
WEED_PALETTE_A8       1024
WEED_PALETTE_A1       1025
WEED_PALETTE_AFLOAT   1064
}}}

The range for AFLOAT when used to hold transparency values is 0.0 (fully transparent) to 1.0 (fully opaque).
Such channels may also be used to hold other types of float data arrays, in which case the range may differ.


Palette numbers >=8192 are reserved for custom palettes.

=== Extending the palette list ===

The default palette list can be supplemented with additional custom palette types.
The section below, "WEED_ADVANCED_PALETTES" provides more details.



==== Gamma types (api 200 and above) ====

 * WEED_GAMMA_UNKNOWN 0

 * WEED_GAMMA_LINEAR -1

 * WEED_GAMMA_SRGB 1 (IEC 61966-2-4)

 * WEED_GAMMA_BT709 2 (should this be BT.1886 ?)

Gamma types >=512 are reserved for custom gamma types.


==== YUV sampling types ====
     These definitions are somewhat unclear, and may be augmented in the future.


 * WEED_YUV_SAMPLING_DEFAULT  0  : Default subsampling.

 * WEED_YUV_SAMPLING_JPEG  0   : Chroma is sampled at half the horizontal
   and half the vertical frequency. (YUV 4:2:0). Chroma samples are
   alternated horizontally between luma samples (like yuyv-yuyv)
   The vertical alignment is unclear.

 * WEED_YUV_SAMPLING_MPEG  1  : Same as JPEG, but Chroma samples are
   horizontally aligned. There is notion of fields. Note: only mpeg2 uses this, mpeg1 uses JPEG sampling.
   The vertical alignment is unclear.
   (YUV 4:2:0 only) (like yuvy-yuvy)

 * WEED_YUV_SAMPLING_DVPAL  2  : Subsampling per field, chroma samples
   are located above and below luma samples, and CB and CR samples are located on alternate lines (YUV 4:2:0) 
   The horizontal alignment is unclear.

 * WEED_YUV_SAMPLING_DVNTSC  3  : Chroma is sampled at a reduced
   horizontal frequency but is aligned horizontally with luma samples
   (YUV 4:2:2 / YUV 4:1:1) [similar to mpeg, but vertically aligned] (top left)

Sampling types >= 512 are reserved for custom samplings.



==== YUV clamping ====
     Indicates the value ranges for Y, U and V.

 * WEED_YUV_CLAMPING_CLAMPED aka WEED_YUV_CLAMPING_MPEG   :: the default if not present (clamped to Y: 16 - 235,
   U, V: 16 - 240)                                                 

 * WEED_YUV_CLAMPING_UNCLAMPED  aka WEED_YUV_CLAMPING_JPEG 1  :: Y, U and V are unclamped (full range) 0 - 255

clamping types >= 512 are reserved for custom clampings.



==== YUV subspace ====

 * WEED_YUV_SUBSPACE_YUV    :: Any YUV colourspace may be used, with Y representing the luma 
   channel, and U and V as colour offsets. Optional, since this is the default if not specified. May be used in cases where 
   be used in cases where no conversion to / from RGB or other YUV subspaces are required. Filters with out channels but no
   in channels (i.e. generators) MUST NOT use this value for channels, since the host needs to know how to convert
   the generated frames.

 * WEED_YUV_SUBSPACE_YCBCR     :: Standard YUV (Y'CbCr ITU-R BT.601) using conversion
   factors (Kr=0.299, Kb=0.114, UV offset 128). The plugin should specify this if for example 
   it sends to or receives from external sources.

 * WEED_YUV_SUBSPACE_BT709 aka WEED_YUV_SUBSPACE_ITU709     :: ITU-R BT.709 high definition TV which uses different
   conversion factors than Y'CbCr digital/ananlog (Kr=0.2125, Kb=0.0721, UV offset 128)

subspace types >= 512 are reserved for custom subspaces.




== NOTE ABOUT COLOUR SPACES ==
Channels with alpha:

Alpha is always POST MULTIPLIED in Weed, unless the host sets the WEED_HOST_SUPPORTS_PREMULTIPLIED_ALPHA bit
in the HOST_INFO "flags" AND the plugin sets WEED_FILTER_PREF_PREMULTIPLIED_ALPHA in the filter flags.
(Even then the value of "alpha_premultiplied" should be checked in each channel).



Gamma types:
As of API version 200, Weed effect plugins may choose to operate in the LINEAR (i.e. perceptual) gamma space.
This means that for RGB type palettes, the component values (R, G, B) represent the values which are displayed on the monitor.

For example, since the human eye perceives darker values more strongly than lighter values, a mid-grey in this colour space has
an (R, G, B) value of (55, 55, 55). This colour space is used since it is much better for calculating visual brightness (luma)
values, and for mixing (adding) and multiplying colour values perceptually. Thus all colour "pixel_data" values for RGB(A) will
be supplied by the host or generated by the filter using this colour space ('transfer function' to be more precise).

In addition to the "pixel_data" values, the R, G, B VALUEs of any WEED_PARAM_COLOR type parameters will be maintained to this
colour space by the host, although they mau be displayed differently to the user.

So for example if the user entered (127, 127, 127) for a colour value in the GUI, then the filter would
receive the values (55, 55, 55). When creating the parameter templates, the DEFAULT and NEW_DEFAULT values should also be
in linear gamma. (For float types, the equivalent is 0.5 ~= 0.181818...).

If the host supports this, it will set the WEED_HOST_SUPPORTS_LINEAR_GAMMA bit in the HOST_INFO "flags".

The plugin may then set the flag WEED_FILTER_HINT_LINEAR_GAMMA in filter flags for any filter class.

Subsequently, the host will then set the "gamma_type" leaves for any RGB type CHANNEL instances
and any colour type PARAMETER instances to WEED_GAMMA_LINEAR.

The plugin can request this behaviour be overridden for individual parameters (in or out) by setting the
PARAMETER_TEMPLATE's "gamma_type" leaf to WEED_GAMMA_SRGB.

The host should then leave the VALUEs in the sRGB space and set "gamma_type" to WEED_GAMMA_SRGB for the PARAMETER instance.
Note this applies only to paramters; individual channels cannot be overridden in this manner.

N.B. This mode may be much better for filters that want to mix / overlay channels or colour values,
or use perceptual brightness values without any reference to absolute colour values. 










== OUTLINE WEED PROCESS FLOW OVERVIEW ==

 * Host calls weed_init(), passing in the weed api version it wants to use. If successful, the function sets the core Weed functions
   for the host.

 *  Host loads plugin (using dlopen)

 *  Host calls the weed_setup() function in the plugin, passing in a pointer to the bootstrap function (normally this would be
    weed_bootstrap in the weed-utils library.

 *  plugin calls the bootstrap function, passing an address to return the default getter function, as well as the minimum and
    maximum weed and filter api versions the plugin supports. The library checks weed and filter api_versions supported by
    the plugin. If either host version is less then the plugin minumin version the plugin
    cannot be loaded. If one or both of the values are greater than the maximum, the library checks for compatibility.
    If the host version and plugin version are incompatible, the plugin cannot be loaded so NULL is returned. Otherwise it is OK
    to proceed. The weed_boostrap function will create a HOST_INFO plant and set leaves with the host api versions,
    pointers to the functions the plugin should use, and return it to the plugin, as well as setting the default getter function,
    Optionally, the library will call a callback function in the host before returning the PLUGIN_INFO, so that the host can
    check, alter or add leaves before it is returned to the plugin.


*  if the HOST_INFO is NULL, the plugin MUST return NULL from its weed_setup() function. Otherwise the plugin uses the
   default_getter to get the leaves of the HOST_INFO plant until it has enough functions defined to use the normal
   Weed get function for its weed api version. Then it uses this to get the remaining leaves. Once this is done it creates a
   PLUGIN_INFO plant. All this would normally be done in the weed-plugin-utils library, weed_plugin_info_init().




All of this is simplified by the Weed utility libraries. The host simply calls weed_setup() in the plugin, passing in
weed_bootstrap as the only parameter, and receives back a PLUGIN_INFO.


On the plugin side, a simple macro taking 2 parameters, the maximum weed and filter APIs supported, may be used to call the
bootstrap function and initialise the PLUGIN_INFO, returning NULL to the host if it is NULL. The minimum API versions are assumed
to be equal to the maximum versions. A different variation of the macro can be used which takes an additional 2 parameters if the
plugin author wants to specify lower minimum values.





When host wants to use the plugin,

 * Host creates a FILTER_INSTANCE: Host examines the in_channel and out_channel plants, and sets the "disabled" flag for any optional channels it does not wish to use. It also checks "palette_list", selects a palette it would like to start using on that channel and sets the chosen value in the "current_palette" leaf. It also sets the sizes ("width" and "height" leaves) if the plugin left them as zero. All input parameters have to have values set at this point. This means host now has a plant that it will instantiate.

 * Host calls init_func() [if it exists] from the filter info plant, passing a pointer to a FILTER_INSTANCE it would like to instantiate.

* Plugin now knows the channel sizes, palettes and which channels are in use. The plugin may now weed_malloc() internal data.

 * Host may now change parameter values (respecting "max" and "min" leaves) and it after that it may call process_func() in the plugin, passing in the initialised FILTER_INSTANCE. 
 * When the host has finished with the FILTER_INSTANCE, or if it needs
   to re-initialise it, the host must call deinit_func() in the plugin
 [if the plugin has one], passing in a pointer to the FILTER_INSTANCE. The plugin MUST now weed_free() any internally allocated data.

 * Host can now weed_plant_free() the FILTER_INSTANCE, or it can reuse the FILTER_INSTANCE by calling init_func() once more.




== Plugin locations ==

The list of directories to be searched can be set in the environment
variable WEED_PLUGIN_PATH; directories in WEED_PLUGIN_PATH should be separated by
colons (:) the indicated directory and ONE LEVEL OF SUDIRECTORIES
should be searched for each entry.

shared Icons may be placed in a /icons subdirectory., and at a plugin author's discretion, a package may install icons in icons/<packagename> 

Readonly data files  may be placed in a /data subdirectory for shared data, and during installation a package may choose to install
readonly files in data/<packagename> directory, where <packagename> is the well known name of the package,
usually, but not always equivalent to the .so name of the plugin supplying the filter class(es).



== Weed hashnames ==

For exchanging filter references between hosts, the following schema is suggested:

let weed hashname be a concatenation of the following:

<package_name>|<filter_name>|<author>


where:
<package_name> is the value of the "package_name" leaf set in the plugin_info of the plugin.

if the package name is not defined then the plugin name (library name without directory or file extension) should be used instead.

<filter_name> : the string value defined in the "name" leaf of the filter_class.

<author> : the string value defined in the "author" leaf of the filter_class.


Let weed version hashname be:

<package_name>|<filter_name>|<author>|<version>.<micro_version>

where:
<version> is the value of the "version" leaf in the filter_class (not the plugin_info leaf !)

<micro_version> is the value of the optional "micro_version" leaf in the filter_class.
The value may be omitted, and then assumed to be 0. Otherwise, a host may use a higher micro_version
provided it can handle non-breaking changes (e.g. extra parameters / values / optional channels)

If micro_version is 0 or undefined then this may be shortened to:

<package_name>|<filter_name>|<author>|<version>



Package names are case insneitive and may consist only of alphanumeric characters plus '_'.
Some package names are reserved and should not be used generally.

Examples of reserved names are:

"weed" : reserved for reference filters.

"frei0r" : reserved for the frei0r project (there is a reference Weed filter which wraps frei0r plugins for Weed)

"ladspa" : reserved for the LADSPA project (there is a reference Weed filter which wraps frei0r plugins for Weed)

"libvisual" : reserved for the libvisual project (there is a reference Weed filter which wraps frei0r plugins for Weed)


"data", "icons" : reserved for package data directories and icon directories.


Names such as "doc", "docs", "Documents", "lib", "shared", "AppData"
		  	       etc. which are names of commonly known subdirectories should also be
			       avoided since creating package
			       subdirectories with these names could cause confusion.









==== Plugin threading ====

Filter_class flag WEED_FILTER_HINT_MAY_THREAD

   The plugin can set this if it can still produce its output when the destination frame is subdivided into non-overlapping,
   contiguous horizontal areas each with a reduced height.

   In this case, the process_func() may be called several times with the same timecode, and with a partial copy of the instance for
   each thread.

   In the thread instances,
   every non-disabled out channel will have an extra "offset" leaf, and the height leaf will now contain 2 values,
   height[0] is the reduced height height[1] is the real height.

   The "offset" leaf shall contain the offset in rows of the start of the thread's block from the start of the out channel
   pixel_data.

   The plugin MUST only write to the destination rows between offset and offset + height[0] - 1.

   When allocating the slices, the host MUST take into consideration any "vstep" value set by the host in the out channel template.
   and ensure that each slice is a multiple of this value.

   Each thread MUST ONLY write to the out channels in the rows from offset to offset + height[0].

   The plugin may read from any area of the input channel(s) pixel_data, but be aware that if
   the plugin is running "inplace" then the values read from the in channels may or may not have been processed by another thread.

   Thus this hint should only be combined with inplace IF each pixel retains its original position in the output and does not
   depend on the values of pixels in other rows.

   The host should create a copy of the instance for each thread. The copies should have duplicated output channels,
   thus the host can set the "offset" and "height" leaves for the channels to differing values for each thread. The copies
   may retain the origin in_parameters and in_channels.

   The instance passed to the thread with offset 0 should be the one used  by the host to make new copies.
   This means that the thread with offset 0 (the master thread) can update internal values each frame
   (provided the values are in stored in normal "plugin_*" leaves with fundamental types,
   and not in shared memory (allocated) pointed to), and the new values will be readable by all the threads on the subsequent frame.
   In this way the plugin may update its internal state consistently. 

   Note that voidptr values are copied by reference. Thus any internal data (allocated memory) referenced by VOIDPTR
   will still be shared, as will the in / out pixel_data (and audio data).

   Care must be taken if the filter has output parameters to ensure that only the master thread updates the values.

   Any thread may return an error code (plugin_invalid, filter_invalid, memory error, etc.) in which case the order of precedence
   of error values should be observed.
   e.g. if one thread returns plugin_invalid and another returns filter_invalid, the plugin_invalid takes precedence.


-- Tips for plugin writers --
Plugins should support as many palettes as possible.

If using weed-plugin-utils.c:

IF a filter simply moves pixels around, without regard to color in the pixel, then before inclung weed-plugin-utils.h and
weed-plugin-utils.cm put:

#define NEED_PALETTE_UTILS

in the setup function, put:

int palette_list[] = ALL_PACKED_PALETTES_PLUS;

and in the process function, obtain the pixel size with:

int palette = weed_channel_get_palette(channel);
int psize = pixel_size(palette);


If the filter needs to get to the colors inside the pixel, put:

int palette_list[] = ALL_RGB_PALETTES;

to skip the alpha value:

int offs = rgb_offset;

then each row should look like:

for (x = offs; x < width * psize; x += psize) {

    // process 3 bytes color

    //  - BGR and BGRA have the red / blue channels swapped

    // skip 1 byte alpha
}


when jumping to the next row, increment the width by:

dst += orowstride - width * psize;
src += irowstride - width * psize;







Tips for the Weed host.

=== Layers ===

Channel instances can be created with no link to a filter instance. These are know as "layers" in Weed terminology.

A layer can have the same leaves as a channel instance, e.g "width", "height", "rowstrides", "current_palette", "pixel_data"
and can be manipulated internally by the host.

When calling the process_func() for a plugin, the relevant leaves can simply be copied to or from an in or out channel in the instance.

libweed-layers will provide an API for the integrated layers architecture.







Before setting the value of parameters from external sources it is best to check that the value match in both quantity and type.

For example:


SETTING PLUGIN PARAMETERS FROM EXTERNAL SOURCES

#include <weed/weed-host.h>
#include <weed.h>
#include <weed-effects.h>

#define MAX_PARAMS 256

static int ext_set_param(ext_context *ctx, int index, int nvalues, void *values) {
       // values should be a pointer to an array of correct size and type ; e.g  (void *)&(int[nvalues])

       weed_plan weed_plant_t *inst = (weed_plant_t *)ctx->priv_data;
       weed_plant_t **in_params;
       weed_plant_t *param;
       int nparams, vsize;
       int32_t flags;

       if (!inst) return (int)WEED_ERROR_NOSUCH_LEAF;

       in_params = weed_get_in_params(inst, &nparams);

        if (index >= nparams) {
	  weed_free(in_params);
	  return (int)WEED_ERROR_NOSUCH_ELEMENT;
	}

	param = in_params[index];
	weed_free(in_params);

	/* try to get the existing number of values from "value", and if that doesn't exist, then from "default" */
  	vsize = weed_param_get_value_size(param);
	if (!vsize) vsize = weed_param_get_default_size(param);
      
	if (vsize > 0) {
    	   	  if (nvalues == vsize) {
		     	      /* Ok, that's the correct number of values, but we still need to check the type and then set the "value" */ 
      		     	      return validate_vals(param, 0, nvalues, value);
	}

  	flags = weed_paramtmpl_get_flags(paramtmpl);

  	if (flags & WEED_PARAMETER_VARIABLE_SIZE) {
	   	      		/* it's a list type value, the number of elements just has to be an integer multiple of the value size *\
				/* (i.e n * 3 for RGB, n * 4 for RGBA, n * 1 for everything else, n can even be zero)
      		     	      return validate_vals(param, vsize, nvalues, value);
	}

        // either the user tried to set an invalid number of elements or the plugin was misconfigured
	return EINVAL;
}




static int validate_values(weed_plant_t *param, int is_list, weed_size_t nvalues, void *values) {
	weed_size_t vsize = 0;
	int ptype = weed_param_get_type(param);

         if (ptype == WEED_PARAM_COLOR) {
	   	 if (weed_param_get_cspace(param) == WEED_COLORSPACE_RGBA) vsize = 4; 
    		else vsize = 3;
	}

	if (( !is_list && nvalues != vsize ) || ( is_list && (nvalues % vsize) != 0) ) return EINVAL;

#ifndef CHECK_MIN_MAX
	weed_leaf_set(param, WEED_LEAF_VALUE, nvalues, values);
	return WEED_SUCCESS;
}
#endif


=== WEED_ADVANCED_PALETTES ===

(This is a somewhat experimental feature, so some details may change in the future.)

Weed Advanced Palettes allows the existing default palettes to be defined in a more rigorous fashion,
as well as enabling custom palettes to be added in an organised manner.

This feature may be enabled by defining the preprocessor symbol WEED_ADVANCED_PALETTES before
including weed/weed-palettes.h. The definitions below are then provided by the header.

The weed_macropixel_t struct may be used to define many different types of pixel format.
The fields of the struct are intended to be defined statically
and remain constant for the application lifetime

By design there is no provision here for gamma transfer functions, component ranges, sampling locations,
transformation matrices and the like.

These should be handled outside this struct. If desired, the extended pointer may be used
to reference another struct which contains these other details.


Definitions:

#ifdef WEED_ADVANCED_PALETTES
#define WEED_ADVANCED_PALETTES_VERSION 100

// if desired, the "palette_list" for a filter or channel_template may include WEED_PALETTE_ADVANCED.
// In this case, an additional filter_class leaf "adv_pal_list",
// an array of type WEED_SEED_VOIDPTR should be set for the filter_class or channel_template
// the values should point to statically allocated weed_macropixel_t structs.
// the usual rules about channel_templates overriding filter_class, and palette matching / conversion
// still apply.
//
// in response, the host may set the "current_palette" for a channel to WEED_PALETTE_ADVANCED,
// and set the additional leaf "adv_palette" with type WEED_SEED_VOIDPTR to point to the
// weed_macropixel_t struct selected.


#define WEED_PALETTE_ADVANCED 8191

#define WEED_LEAF_ADVANCED_PALETTE_LIST "adv_pal_list"
#define WEED_LEAF_ADVANCED_PALETTE "adv_palette"

#ifndef MAXPPLANES
#define MAXPPLANES 8
#endif

// built-in component types; these may be added to in the future if there is a need.
// however the range 1 - 511 is reserved for RGB types (colour primaries)
// 512 - 1024 for YUV types
// and 1024 - 2047 for alpha / monochrome types
// 2048 - 4091 for non-display types

#define WEED_VCHAN_end 		0

#define WEED_VCHAN_red 		1
#define WEED_VCHAN_green      	2
#define WEED_VCHAN_blue	       	3

#define WEED_VCHAN_Y			512
#define WEED_VCHAN_U			513
#define WEED_VCHAN_V			514

#define WEED_VCHAN_alpha		1024

#define WEED_VCHAN_FIRST_CUSTOM		8192  ///< channel types >= 8192 are free for custom use

#define WEED_VCHAN_DESC_PLANAR		(1 << 0) ///< planar type
#define WEED_VCHAN_DESC_FP		(1 << 1) ///< floating point type
#define WEED_VCHAN_DESC_BE		(1 << 2) ///< pixel data is big endian (within each component)

#define WEED_VCHAN_DESC_FIRST_CUSTOM	(1 << 16) ///< bits 16 - 31 are free for custom use


typedef struct {
  uint16_t ext_ref;  ///< link to an enumerated type
  uint16_t chantype[MAXPPLANES]; ///  e.g. {WEED_VCHAN_U, WEED_VCHAN_Y, WEED_VCHAN_V, WEED_VCHAN_Y)
  uint32_t flags; /// bitmap of flags, eg. WEED_VCHAN_DESC_FP | WEED_VCHAN_DESC_PLANAR
  uint8_t  hsub[MAXPPLANES];  /// horiz. subsampling, 1 means no subsampling, 2 means halved etc.
  uint8_t  vsub[MAXPPLANES];  /// vert subsampling, a value of (0) means no subsampling
  uint8_t npixels; ///< npixels per macropixel: if undefined (0), a value of 1 is assumed
  uint8_t bitsize[MAXPPLANES]; /// number of bits per component. IF (0), a value of 8 bits is assumed
  void *extended; ///< pointer to app defined data
} weed_macropixel_t;
#endif


Note that MAXPPLANES (the maximum number of pixel planes / components) can be pre-defined if desired,
however the default value of 8 should ensure that weed_macropixel_t struct is exactly 64 bytes,
which is generally considered to be an optimal size for performance considerations.

If the number of planes / components is less then MAXPPLANES, then the last entry
in chantype must be 0 (WEED_VCHAN_end).

For the array fields, the ordering is equivalent to the order in which they would be read from memory
The WEED_VCHAN_DESC_BE flag only describes the byte arrangement within each component.

All of the default WEED palettes can be easily modelled using weed_macropixel_t, i.e:

static weed_macropixel_t advp[256];

void init_advanced_palettes(void) {
  memset(advp, 0, 256 * sizeof(weed_macropixel_t));

  advp[0] = (weed_macropixel_t) {WEED_PALETTE_RGB24,
  {WEED_VCHAN_red, WEED_VCHAN_green, WEED_VCHAN_blue}};

  advp[1] = (weed_macropixel_t) {WEED_PALETTE_BGR24,
  {WEED_VCHAN_blue, WEED_VCHAN_green, WEED_VCHAN_red}};

  advp[2] = (weed_macropixel_t) {
    WEED_PALETTE_RGBA32, {WEED_VCHAN_red, WEED_VCHAN_green, WEED_VCHAN_blue,
                          WEED_VCHAN_alpha}};

  advp[3] = (weed_macropixel_t) {
    WEED_PALETTE_BGRA32, {WEED_VCHAN_blue, WEED_VCHAN_green, WEED_VCHAN_red,
                          WEED_VCHAN_alpha}};

  advp[4] = (weed_macropixel_t) {
    WEED_PALETTE_ARGB32, {WEED_VCHAN_alpha, WEED_VCHAN_red, WEED_VCHAN_green,
                          WEED_VCHAN_blue}};

  advp[5] = (weed_macropixel_t) {
    WEED_PALETTE_RGBFLOAT, {WEED_VCHAN_red, WEED_VCHAN_green, WEED_VCHAN_blue},
                           WEED_VCHAN_DESC_FP, {0}, {0}, 1, {32, 32, 32}};

  advp[6] = (weed_macropixel_t) {
    WEED_PALETTE_RGBAFLOAT, {WEED_VCHAN_red, WEED_VCHAN_green,
                             WEED_VCHAN_blue, WEED_VCHAN_alpha},
			     WEED_VCHAN_DESC_FP, {0}, {0}, 1, {32, 32, 32, 32}};

/// yuv planar
  advp[7] = (weed_macropixel_t) {
    WEED_PALETTE_YUV420P, {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V},
                          WEED_VCHAN_DESC_PLANAR, {1, 2, 2}, {1, 2, 2}};

  advp[8] = (weed_macropixel_t) {
    WEED_PALETTE_YVU420P, {WEED_VCHAN_Y, WEED_VCHAN_V, WEED_VCHAN_U},
                          WEED_VCHAN_DESC_PLANAR, {1, 2, 2}, {1, 2, 2}};

  advp[9] = (weed_macropixel_t) {
    WEED_PALETTE_YUV422P, {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V},
                          WEED_VCHAN_DESC_PLANAR, {1, 2, 2}, {1, 1, 1}};

  advp[10] = (weed_macropixel_t) {
    WEED_PALETTE_YUV444P, {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V},
                          WEED_VCHAN_DESC_PLANAR};

  advp[11] = (weed_macropixel_t) {
    WEED_PALETTE_YUVA4444P, {WEED_VCHAN_Y, WEED_VCHAN_U,
                             WEED_VCHAN_V, WEED_VCHAN_alpha},
			     WEED_VCHAN_DESC_PLANAR};

/// yuv packed
  advp[12] = (weed_macropixel_t) {
    WEED_PALETTE_UYVY, {WEED_VCHAN_U, WEED_VCHAN_Y, WEED_VCHAN_V, WEED_VCHAN_Y}, 0, {0}, {0}, 2};

  advp[13] = (weed_macropixel_t) {
    WEED_PALETTE_YUYV, {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_Y, WEED_VCHAN_V}, 0, {0}, {0}, 2};

  advp[14] = (weed_macropixel_t) {WEED_PALETTE_YUV888, {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V}};

  advp[15] = (weed_macropixel_t) {
    WEED_PALETTE_YUVA8888, {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V, WEED_VCHAN_alpha}};

  advp[16] = (weed_macropixel_t) {
    WEED_PALETTE_YUV411, {WEED_VCHAN_U, WEED_VCHAN_Y, WEED_VCHAN_Y,
                          WEED_VCHAN_V, WEED_VCHAN_Y, WEED_VCHAN_Y}, 0, {0}, {0}, 4};

  /// alpha
  advp[17] = (weed_macropixel_t) {WEED_PALETTE_A8, {WEED_VCHAN_alpha}};

  advp[18] = (weed_macropixel_t) {WEED_PALETTE_A1, {WEED_VCHAN_alpha}, 0, {0}, {0}, 1, {1}};

  advp[19] = (weed_macropixel_t) {WEED_PALETTE_AFLOAT, {WEED_VCHAN_alpha}, WEED_VCHAN_DESC_FP, {0}, {0}, 1, {32}};

  advp[20] = (weed_macropixel_t) {WEED_PALETTE_END}; /// indicates the end of the default palettes


The palettes can then be manipulated programmatically, for example:

const weed_macropixel_t *get_advanced_palette(int weed_palette) {
  for (register int i = 0; advp[i].ext_ref != WEED_PALETTE_END; i++)
    if (advp[i].ext_ref == weed_palette) return &advp[i];
  return NULL;
}

boolean palette_has_alpha(int pal) {
  const weed_macropixel_t *mpx = get_advanced_palette(pal);
  if (mpx) {
    for (register int i = 0; i < MAXPPLANES && mpx->chantype[i]; i++)
      if (mpx->chantype[i] == WEED_VCHAN_alpha) return TRUE;
  }
  return FALSE;
}


In addition, it is a simple matter to extend the palette defintions. Here are some examples:


ABGR32:

 advp[21] = (weed_macropixel_t) {
    CUST_PALETTE_ABGR32, {WEED_VCHAN_alpha, WEED_VCHAN_blue, WEED_VCHAN_green,
                          WEED_VCHAN_red}};


yvu422 planar (u and v channels swapped, horizontal subsampling):

 advp[22] = (weed_macropixel_t) {
    CUST_PALETTE_YVU422P, {WEED_VCHAN_Y, WEED_VCHAN_V, WEED_VCHAN_U},
    WEED_VCHAN_DESC_PLANAR, {1, 2, 2}, {1, 1, 1}};


yuva420p (yuv420 planar with an added alpha plane):

advp[23] = (weed_macropixel_t) {
    CUST_PALETTE_YUVA420P, {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V, WEED_VCHAN_alpha},
                            WEED_VCHAN_DESC_PLANAR, {1, 2, 2, 1}, {1, 2, 2, 1}};

ayuv8888 (packed alpha, y, u, v, 8 bits per channel, no subsampling):

advp[24] = (weed_macropixel_t) {
    CUST_PALETTE_AYUV8888, {WEED_VCHAN_alpha, WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V}};


yuv packed pixel 32 bit float per channel:

advp[25] = (weed_macropixel_t) {
    CUST_PALETTE_YUVFLOAT, {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V},
                            WEED_VCHAN_DESC_FP, {0}, {0}, 1, {32, 32, 32}};

yuva packed pixel 32 bit float per channel:

advp[26] = (weed_macropixel_t) {
    CUST_PALETTE_YUVAFLOAT, {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V,
                              WEED_VCHAN_alpha},
			      WEED_VCHAN_DESC_FP, {0}, {0}, 1, {32, 32, 32, 32}};

rgb 16 bits per channel, big endian:

advp[27] = (weed_macropixel_t) {
    CUST_PALETTE_RGB48, {WEED_VCHAN_red, WEED_VCHAN_green, WEED_VCHAN_blue},
                         WEED_VCHAN_DESC_BE, {0}, {0}, 1, {16, 16, 16}};

rgba 16 bits per channel, big endian:

advp[28] = (weed_macropixel_t) {
    CUST_PALETTE_RGBA64, {WEED_VCHAN_red, WEED_VCHAN_green, WEED_VCHAN_blue,
                           WEED_VCHAN_alpha}, WEED_VCHAN_BE, {0}, {0}, 1, {16, 16, 16, 16}};


yuv 12/10/10 packed, no subsampling:

advp[29] = (weed_macropixel_t) {
    CUST_PALETTE_YUV121010, {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V},
                             0, {0}, {0}, 1, {12, 10, 10}};

or we can get creative:

32 bit y; 16 bit alpha; 16 bit v / 16 bit u subsampled horizontally / vertically, planar
(64 bits per pixel)

advp[30] = (weed_macropixel_t) {
    CUST_PALETTE_YAVUP_VARIANT, {WEED_VCHAN_Y, WEED_VCHAN_ALPHA, WEED_VCHAN_V, WEED_VCHAN_U},
                             WEED_VCHAN_DESC_PLANAR, {1, 1, 2, 1}, {1, 1, 1, 2}, 1, {32, 16, 16, 16}};







Appendix A. Weed Utlity functions:

For the HOST:

#define WEED_LEAF_GET(plant, key, type) weed_get_##type##_value(plant, key, NULL)
#define WEED_LEAF_GET_ARRAY_COUNTED(plant, key, type, counter) weed_get_##type##_array_counted(plant, key, &count)
#define WEED_LEAF_SET(plant, key, type, value) weed_set_##type##_value(plant, key, value)
#define WEED_LEAF_SET_ARRAY(plant, key, type, nvals, array) weed_set_##type##_array(plant, key, nvals, array)

/* check if leaf exists and has a value */
int weed_plant_has_leaf(weed_plant_t *, const char *key);

/* check if leaf exists; may have a seed_type but no value set */
int weed_leaf_exists(weed_plant_t *, const char *key);

void weed_utils_set_custom_memfuncs(weed_malloc_f malloc_func, weed_calloc_f calloc_func, weed_memcpy_f memcpy_func,
                                    weed_memcmp_f memcmp_func, weed_free_f free_func);

weed_error_t weed_set_int_value(weed_plant_t *, const char *key, int32_t value);
weed_error_t weed_set_double_value(weed_plant_t *, const char *key, double value);
weed_error_t weed_set_boolean_value(weed_plant_t *, const char *key, int32_t value);
weed_error_t weed_set_int64_value(weed_plant_t *, const char *key, int64_t value);
weed_error_t weed_set_string_value(weed_plant_t *, const char *key, const char *value);
weed_error_t weed_set_funcptr_value(weed_plant_t *, const char *key, void *value);
weed_error_t weed_set_voidptr_value(weed_plant_t *, const char *key, void *value);
weed_error_t weed_set_plantptr_value(weed_plant_t *, const char *key, weed_plant_t *value);
weed_error_t weed_set_custom_value(weed_plant_t *, const char *key, uint32_t seed_type, void *value);

int32_t weed_get_int_value(weed_plant_t *, const char *key, weed_error_t *error);
double weed_get_double_value(weed_plant_t *, const char *key, weed_error_t *error);
int32_t weed_get_boolean_value(weed_plant_t *, const char *key, weed_error_t *error);
int64_t weed_get_int64_value(weed_plant_t *, const char *key, weed_error_t *error);
char *weed_get_string_value(weed_plant_t *, const char *key, weed_error_t *error);
weed_funcptr_t weed_get_funcptr_value(weed_plant_t *, const char *key, weed_error_t *error);
void *weed_get_voidptr_value(weed_plant_t *, const char *key, weed_error_t *error);
weed_plant_t *weed_get_plantptr_value(weed_plant_t *, const char *key, weed_error_t *error);
void *weed_get_custom_value(weed_plant_t *, const char *key, uint32_t seed_type, weed_error_t *error);

weed_error_t weed_set_int_array(weed_plant_t *, const char *key, weed_size_t num_elems, int32_t *values);
weed_error_t weed_set_double_array(weed_plant_t *, const char *key, weed_size_t num_elems, double *values);
weed_error_t weed_set_boolean_array(weed_plant_t *, const char *key, weed_size_t num_elems, int32_t *values);
weed_error_t weed_set_int64_array(weed_plant_t *, const char *key, weed_size_t num_elems, int64_t *values);
weed_error_t weed_set_string_array(weed_plant_t *, const char *key, weed_size_t num_elems, char **values);
weed_error_t weed_set_funcptr_array(weed_plant_t *, const char *key, weed_size_t num_elems, weed_funcptr_t *values);
weed_error_t weed_set_voidptr_array(weed_plant_t *, const char *key, weed_size_t num_elems, void **values);
weed_error_t weed_set_plantptr_array(weed_plant_t *, const char *key, weed_size_t num_elems, weed_plant_t **values);
weed_error_t weed_set_custom_array(weed_plant_t *, const char *key, uint32_t seed_type, weed_size_t num_elems, void **values);

int32_t *weed_get_int_array(weed_plant_t *, const char *key, weed_error_t *error);
double *weed_get_double_array(weed_plant_t *, const char *key, weed_error_t *error);
int32_t *weed_get_boolean_array(weed_plant_t *, const char *key, weed_error_t *error);
int64_t *weed_get_int64_array(weed_plant_t *, const char *key, weed_error_t *error);
char **weed_get_string_array(weed_plant_t *, const char *key, weed_error_t *error);
weed_funcptr_t *weed_get_funcptr_array(weed_plant_t *, const char *key, weed_error_t *error);
void **weed_get_voidptr_array(weed_plant_t *, const char *key, weed_error_t *error);
weed_plant_t **weed_get_plantptr_array(weed_plant_t *, const char *key, weed_error_t *error);
void **weed_get_custom_array(weed_plant_t *, const char *key, uint32_t seed_type, weed_error_t *error);

int32_t *weed_get_int_array_counted(weed_plant_t *, const char *key, int *count);
double *weed_get_double_array_counted(weed_plant_t *, const char *key, int *count);
int32_t *weed_get_boolean_array_counted(weed_plant_t *, const char *key, int *count);
int64_t *weed_get_int64_array_counted(weed_plant_t *, const char *key, int *count);
char **weed_get_string_array_counted(weed_plant_t *, const char *key, int *count);
weed_funcptr_t *weed_get_funcptr_array_counted(weed_plant_t *, const char *key, int *count);
weed_voidptr_t *weed_get_voidptr_array_counted(weed_plant_t *, const char *key, int *count);
weed_plant_t **weed_get_plantptr_array_counted(weed_plant_t *, const char *key, int *count);
weed_voidptr_t *weed_get_custom_array_counted(weed_plant_t *, const char *key, uint32_t seed_type, int *count);

/* make a copy dest leaf from src leaf. Pointers are copied by reference only, but strings are allocated */
weed_error_t weed_leaf_copy(weed_plant_t *dest, const char *keyt, weed_plant_t *src, const char *keyf);

/* copy only the nth element; if either leaf has n or fewer elements then WEED_ERROR_NOSUCH_ELEMENT is returned */
weed_error_t weed_leaf_copy_nth(weed_plant_t *dst, const char *keyt, weed_plant_t *src, const char *keyf, int n);

/* convenience functions for the more common case where both keys match */
weed_error_t weed_leaf_dup(weed_plant_t *dst, weed_plant_t *src, const char *key);
weed_error_t weed_leaf_dup_nth(weed_plant_t *dst, weed_plant_t *src, const char *key, int n);


/* returns WEED_TRUE if nth elements of 2 leaves are identical (both exist, both seed_types equal, both values equal)
     if elem < 0, then all elements must match */
int weed_leaf_elements_equate(weed_plant_t *p0, const char *k0, weed_plant_t *p1, const char *k1, int elem);

/* copy all leaves in src to dst using weed_leaf_copy */
weed_plant_t *weed_plant_copy(weed_plant_t *src);

/* returns the value of the "type" leaf; returns WEED_PLANT_UNKNOWN if plant is NULL */
int32_t weed_get_plant_type(weed_plant_t *);

/* returns WEED_TRUE if higher and lower versions are compatible, WEED_FALSE if not */
int check_weed_abi_compat(int32_t higher, int32_t lower);

/* returns WEED_TRUE if higher and lower versions are compatible, WEED_FALSE if not */
int check_filter_api_compat(int32_t higher, int32_t lower);

/* set a host callback function to be called from within weed_bootstrap() */
void weed_set_host_info_callback(weed_host_info_callback_f, void *user_data);

/* host only functions */
// set flags for each leaf in a plant. If ign_prefix is not NULL, ignore leaves with keys that begin with ign_prefix
// this enables a host to do: weed_add_plant_flags(plant, WEED_FLAG_IMMUTABLE | WEED_FLAG_UNDELETABLE, "plugin_")
void weed_add_plant_flags(weed_plant_t *, int32_t flags, const char *ign_prefix);
void weed_clear_plant_flags(weed_plant_t *t, int32_t flags, const char *ign_prefix);



For the PLUGIN:

weed_plant_t *weed_bootstrap(weed_default_getter_f *, int32_t plugin_weed_min_api_version, int32_t plugin_weed_max_api_version,
                             int32_t plugin_filter_min_api_version, int32_t plugin_filter_max_api_version);

/* check if leaf exists and has a value */
int weed_plant_has_leaf(weed_plant_t *, const char *key);

weed_error_t weed_set_int_value(weed_plant_t *, const char *key, int32_t value);
weed_error_t weed_set_double_value(weed_plant_t *, const char *key, double value);
weed_error_t weed_set_boolean_value(weed_plant_t *, const char *key, int32_t value);
weed_error_t weed_set_int64_value(weed_plant_t *, const char *key, int64_t value);
weed_error_t weed_set_string_value(weed_plant_t *, const char *key, const char *value);
weed_error_t weed_set_funcptr_value(weed_plant_t *, const char *key, void *value);
weed_error_t weed_set_voidptr_value(weed_plant_t *, const char *key, void *value);
weed_error_t weed_set_plantptr_value(weed_plant_t *, const char *key, weed_plant_t *value);

int32_t weed_get_int_value(weed_plant_t *, const char *key, weed_error_t *error);
double weed_get_double_value(weed_plant_t *, const char *key, weed_error_t *error);
int32_t weed_get_boolean_value(weed_plant_t *, const char *key, weed_error_t *error);
int64_t weed_get_int64_value(weed_plant_t *, const char *key, weed_error_t *error);
char *weed_get_string_value(weed_plant_t *, const char *key, weed_error_t *error);
weed_funcptr_t weed_get_funcptr_value(weed_plant_t *, const char *key, weed_error_t *error);
void *weed_get_voidptr_value(weed_plant_t *, const char *key, weed_error_t *error);
weed_plant_t *weed_get_plantptr_value(weed_plant_t *, const char *key, weed_error_t *error);

weed_error_t weed_set_int_array(weed_plant_t *, const char *key, weed_size_t num_elems, int32_t *values);
weed_error_t weed_set_double_array(weed_plant_t *, const char *key, weed_size_t num_elems, double *values);
weed_error_t weed_set_boolean_array(weed_plant_t *, const char *key, weed_size_t num_elems, int32_t *values);
weed_error_t weed_set_int64_array(weed_plant_t *, const char *key, weed_size_t num_elems, int64_t *values);
weed_error_t weed_set_string_array(weed_plant_t *, const char *key, weed_size_t num_elems, char **values);
weed_error_t weed_set_funcptr_array(weed_plant_t *, const char *key, weed_size_t num_elems, weed_funcptr_t *values);
weed_error_t weed_set_voidptr_array(weed_plant_t *, const char *key, weed_size_t num_elems, void **values);
weed_error_t weed_set_plantptr_array(weed_plant_t *, const char *key, weed_size_t num_elems, weed_plant_t **values);

int32_t *weed_get_int_array(weed_plant_t *, const char *key, weed_error_t *error);
double *weed_get_double_array(weed_plant_t *, const char *key, weed_error_t *error);
int32_t *weed_get_boolean_array(weed_plant_t *, const char *key, weed_error_t *error);
int64_t *weed_get_int64_array(weed_plant_t *, const char *key, weed_error_t *error);
char **weed_get_string_array(weed_plant_t *, const char *key, weed_error_t *error);
weed_funcptr_t *weed_get_funcptr_array(weed_plant_t *, const char *key, weed_error_t *error);
void **weed_get_voidptr_array(weed_plant_t *, const char *key, weed_error_t *error);
weed_plant_t **weed_get_plantptr_array(weed_plant_t *, const char *key, weed_error_t *error);

int32_t *weed_get_int_array_counted(weed_plant_t *, const char *key, int *count);
double *weed_get_double_array_counted(weed_plant_t *, const char *key, int *count);
int32_t *weed_get_boolean_array_counted(weed_plant_t *, const char *key, int *count);
int64_t *weed_get_int64_array_counted(weed_plant_t *, const char *key, int *count);
char **weed_get_string_array_counted(weed_plant_t *, const char *key, int *count);
weed_funcptr_t *weed_get_funcptr_array_counted(weed_plant_t *, const char *key, int *count);
weed_voidptr_t *weed_get_voidptr_array_counted(weed_plant_t *, const char *key, int *count);
weed_plant_t **weed_get_plantptr_array_counted(weed_plant_t *, const char *key, int *count);



For the HOST:
Weed Host Utils (in development)

/* general Weed functions and definitions */
int32_t weed_plant_get_type(weed_plant_t *);

int WEED_PLANT_IS_PLUGIN_INFO(weed_plant_t *);
int WEED_PLANT_IS_HOST_INFO(weed_plant_t *);
int WEED_PLANT_IS_FILTER_CLASS(weed_plant_t *);
int WEED_PLANT_IS_FILTER_INSTANCE(weed_plant_t *);
int WEED_PLANT_IS_CHANNEL_TEMPLATE(weed_plant_t *);
int WEED_PLANT_IS_CHANNEL(weed_plant_t *);
int WEED_PLANT_IS_PARAMETER_TEMPLATE(weed_plant_t *);
int WEED_PLANT_IS_PARAMETER(weed_plant_t *);
int WEED_PLANT_IS_GUI(weed_plant_t *);

/* FILTER functions */
int weed_filter_get_flags(weed_plant_t *filter);
int weed_filter_is_resizer(weed_plant_t *filter);
weed_plant_t **weed_filter_get_in_chantmpls(weed_plant_t *filter, int *ntmpls);
weed_plant_t **weed_filter_get_out_chantmpls(weed_plant_t *filter, int *ntmpls);
weed_plant_t **weed_filter_get_in_paramtmpls(weed_plant_t *filter, int *ntmpls);
weed_plant_t **weed_filter_get_out_paramtmpls(weed_plant_t *filter, int *ntmpls);
weed_plant_t *weed_filter_get_gui(weed_plant_t *filter);

/* FILTER_INSTANCE functions */
weed_plant_t **weed_instance_get_out_channels(weed_plant_t *instance, int *nchans);
weed_plant_t **weed_instance_get_in_channels(weed_plant_t *instance, int *nchans);
weed_plant_t **weed_instance_get_in_params(weed_plant_t *instance, int *nparams);
weed_plant_t **weed_instance_get_out_params(weed_plant_t *instance, int *nparams);

/* CHANNEL_TEMPLATE functions */
int weed_chantmpl_get_flags(weed_plant_t *chantmpl);
int weed_chantmpl_is_optional(weed_plant_t *chantmpl);
int *weed_chantmpl_get_palette_list(weed_plant_t *filter, weed_plant_t *chantmpl, int *nvals) WARN_UNUSED;

/* a return value of zero means unlimited repeats */
int weed_chantmpl_get_max_repeats(weed_plant_t *chantmpl);

/* CHANNEL functions */
void *weed_channel_get_pixel_data(weed_plant_t *channel);

/// width in macropixels, normal value for channels etc.
int weed_channel_get_width(weed_plant_t *channel);
int weed_channel_get_height(weed_plant_t *channel);
int weed_channel_get_palette(weed_plant_t *channel);
int weed_channel_get_palette_details(weed_plant_t *channel, int *YUV_clamping, int *YUV_sampling, int *YUV_subspace);
int weed_channel_get_rowstride(weed_plant_t *channel);
int *weed_channel_get_rowstrides(weed_plant_t *channel, int *nplanes);
int weed_channel_is_disabled(weed_plant_t *channel);
weed_plant_t *weed_channel_get_template(weed_plant_t *channel);

/// width in pixels: only relevant when comparing widths of diferrent palettes
int weed_channel_get_width_pixels(weed_plant_t *channel);

// audio channels
int weed_channel_get_audio_rate(weed_plant_t *channel);
int weed_channel_get_naudchans(weed_plant_t *channel);
int weed_channel_get_audio_length(weed_plant_t *channel);
float **weed_channel_get_audio_data(weed_plant_t *channel, int *naudchans);

weed_plant_t *weed_channel_set_audio_data(weed_plant_t *channel, float **data, int arate, int naudchans, weed_size_t nsamps);

// paramtmpls
weed_plant_t *weed_paramtmpl_get_gui(weed_plant_t *paramtmpl);
int weed_paramtmpl_get_flags(weed_plant_t *paramtmpl);
int weed_paramtmpl_get_type(weed_plant_t *paramtmpl);
int weed_paramtmpl_value_type(weed_plant_t *paramtmpl);
int weed_paramtmpl_has_variable_size(weed_plant_t *paramtmpl);
int weed_paramtmpl_default_size(weed_plant_t *paramtmpl);
int weed_paramtmpl_does_wrap(weed_plant_t *paramtmpl);
int weed_paramtmpl_hints_string_choice(weed_plant_t *paramtmpl);
int weed_paramtmpl_hints_hidden(weed_plant_t *param);

// params
int weed_param_is_hidden(weed_plant_t *param);
weed_plant_t *weed_param_get_gui(weed_plant_t *param);
weed_plant_t *weed_param_get_template(weed_plant_t *param);
int weed_param_get_type(weed_plant_t *paraml);
int weed_param_has_variable_size(weed_plant_t *param);
int weed_param_get_default_size(weed_plant_t *param);
int weed_param_does_wrap(weed_plant_t *paramtmpl);
int weed_param_get_value_type(weed_plant_t *param);

// utils
char *weed_seed_type_to_text(uint32_t seed_type) WARN_UNUSED;
char *weed_error_to_text(weed_error_t error) WARN_UNUSED;
char *weed_palette_get_name_full(int pal, int clamping, int subspace) WARN_UNUSED;

const char *weed_palette_get_name(int pal);
const char *weed_yuv_clamping_get_name(int clamping);
const char *weed_yuv_subspace_get_name(int subspace);

int weed_palette_get_bits_per_macropixel(int pal);
double weed_palette_get_compression_ratio(int pal);
int weed_palette_is_alpha(int pal);
int weed_palette_is_rgb(int pal);
int weed_palette_is_yuv(int pal);
int weed_palette_is_float(int pal);
int weed_palette_has_alpha_channel(int pal);
double weed_palette_get_plane_ratio_horizontal(int pal, int plane);
double weed_palette_get_plane_ratio_vertical(int pal, int plane);
int weed_palette_get_nplanes(int pal);
int weed_palette_is_valid(int pal);
int weed_palette_get_pixels_per_macropixel(int pal);

For the PLUGIN:

weed-plugin-utils:

#define WEED_SETUP_START(weed_api_version, filter_api_version)
#define WEED_SETUP_START_MINMAX(weed_api_min_version, weed_api_max_version, filter_api_min_version, filter_api_max_version)
#define WEED_SETUP_END

#define WEED_DESETUP_START
#define WEED_DESETUP_END

weed_plant_t *weed_plugin_info_init(weed_bootstrap_f weed_boot,
    int32_t weed_abi_min_version, int32_t weed_abi_max_version,
    int32_t filter_api_min_version, int32_t weed_filter_api_max_version);

int weed_get_api_version(weed_plant_t *plugin_info);

weed_plant_t *weed_channel_template_init(const char *name, int flags);
weed_plant_t *weed_audio_channel_template_init(const char *name, int flags);

weed_plant_t **weed_clone_plants(weed_plant_t **plants);

weed_plant_t *weed_filter_class_init(const char *name, const char *author, int version, int flags,
    int *palette_list, weed_init_f init_func,
    weed_process_f process_func, weed_deinit_f deinit_func,
    weed_plant_t **in_chantmpls, weed_plant_t **out_chantmpls,
    weed_plant_t **in_paramtmpls, weed_plant_t **out_paramtmpls);

weed_plant_t *weed_filter_get_gui(weed_plant_t *filter);
weed_plant_t *weed_paramtmpl_get_gui(weed_plant_t *paramt);

void weed_plugin_info_add_filter_class(weed_plant_t *plugin_info, weed_plant_t *filter_class);

// in params
weed_plant_t *weed_text_init(const char *name, const char *label, const char *def);
weed_plant_t *weed_float_init(const char *name, const char *label, double def, double min, double max);
weed_plant_t *weed_switch_init(const char *name, const char *label, int def);
weed_plant_t *weed_integer_init(const char *name, const char *label, int def, int min, int max);
weed_plant_t *weed_colRGBd_init(const char *name, const char *label, double red, double green, double blue);
weed_plant_t *weed_colRGBi_init(const char *name, const char *label, int red, int green, int blue);
weed_plant_t *weed_radio_init(const char *name, const char *label, int def, int group);
weed_plant_t *weed_string_list_init(const char *name, const char *label, int def, const char **const list);
weed_plant_t *weed_param_get_gui(weed_plant_t *param);

// out params
weed_plant_t *weed_out_param_colRGBd_init(const char *name, double red, double green, double blue);
weed_plant_t *weed_out_param_colRGBi_init(const char *name, int red, int green, int blue);
weed_plant_t *weed_out_param_text_init(const char *name, const char *def);
weed_plant_t *weed_out_param_float_init_nominmax(const char *name, double def);
weed_plant_t *weed_out_param_float_init(const char *name, double def, double min, double max);
weed_plant_t *weed_out_param_switch_init(const char *name, int def);
weed_plant_t *weed_out_param_integer_init_nominmax(const char *name, int def);
weed_plant_t *weed_out_param_integer_init(const char *name, int def, int min, int max);

// value setters
void weed_filter_set_flags(weed_plant_t *filter, int flags);
void weed_chantmpl_set_flags(weed_plant_t *chantmpl, int flags);
void weed_paramtmpl_set_flags(weed_plant_t *paramtmpl, int flags);
void weed_gui_set_flags(weed_plant_t *paramtmpl, int flags);
void weed_filter_set_name(weed_plant_t *filter, const char *name);
void weed_chantmpl_set_name(weed_plant_t *chantmpl, const char *name);
void weed_paramtmpl_set_name(weed_plant_t *paramtmpl, const char *name);
//void weed_chantmpl_set_palette_list()

// value getters

// plugin_info
weed_plant_t *weed_get_host_info(weed_plant_t *plugin_info);
int weed_get_api_version(weed_plant_t *plugin_info) ALLOW_UNUSED;

// host info
int weed_get_host_verbosity(weed_plant_t *host_info);
//FN_DECL char *weed_get_host_name(weed_plant_t *host_info);
//FN_DECL char *weed_get_host_version(weed_plant_t *host_info);
int weed_host_get_flags(weed_plant_t *host_info);
int weed_host_supports_linear_gamma(weed_plant_t *host_info);
int weed_host_supports_premultiplied_alpha(weed_plant_t *host_info);
//FN_DECL char **weed_get_host_layout_schemes(weed_plant_t *host_info);

// filter_class
int weed_filter_get_flags(weed_plant_t *filter);
weed_plant_t *weed_filter_get_gui(weed_plant_t *filter) ALLOW_UNUSED;

// param_tmpl
weed_plant_t *weed_paramtmpl_get_gui(weed_plant_t *paramt) ALLOW_UNUSED;
int weed_paramtmpl_get_flags(weed_plant_t *paramtmpl);

// chan tmpl
int weed_chantmpl_get_flags(weed_plant_t *chantmpl);

// inst
weed_plant_t *weed_get_filter_class(weed_plant_t *inst);
weed_plant_t *weed_get_in_channel(weed_plant_t *inst, int idx);
weed_plant_t *weed_get_out_channel(weed_plant_t *inst, int idx);
int weed_instance_get_flags(weed_plant_t *inst);

// channel
void *weed_channel_get_pixel_data(weed_plant_t *channel);
int weed_channel_get_width(weed_plant_t *channel);
int weed_channel_get_height(weed_plant_t *channel);
int weed_channel_get_palette(weed_plant_t *channel);
int weed_channel_get_yuv_clamping(weed_plant_t *channel);
int weed_channel_get_stride(weed_plant_t *channel);

#if defined(NEED_AUDIO) || defined(__LIBWEED_PLUGIN_UTILS__)
int weed_channel_get_audio_rate(weed_plant_t *channel);
int weed_channel_get_naudchans(weed_plant_t *channel);
int weed_channel_get_audio_length(weed_plant_t *channel);
#ifdef __WEED_UTILS_H__
float **weed_channel_get_audio_data(weed_plant_t *channel, int *naudchans);
#endif
#endif

int weed_channel_is_disabled(weed_plant_t *channel);

// params
weed_plant_t  *weed_param_get_template(weed_plant_t *param);
weed_plant_t *weed_param_get_gui(weed_plant_t *param);

// param values
int weed_param_get_value_int(weed_plant_t *param);
int weed_param_get_value_boolean(weed_plant_t *param);
double weed_param_get_value_double(weed_plant_t *param);
int64_t weed_param_get_value_int64(weed_plant_t *param);
char *weed_param_get_value_string(weed_plant_t *param);

#ifdef __WEED_UTILS_H__
int *weed_param_get_array_int(weed_plant_t *param, int *nvalues);
int *weed_param_get_array_boolean(weed_plant_t *param, int *nvalues);
double *weed_param_get_array_double(weed_plant_t *param, int *nvalues);
int64_t *weed_param_get_array_int64(weed_plant_t *param, int *nvalues);
char **weed_param_get_array_string(weed_plant_t *param, int *mvalues);
weed_plant_t **weed_get_in_channels(weed_plant_t *inst, int *nchans);
weed_plant_t **weed_get_out_channels(weed_plant_t *inst, int *nchans);
weed_plant_t **weed_get_in_params(weed_plant_t *inst, int *nparams);
weed_plant_t **weed_get_out_params(weed_plant_t *inst, int *nparams);
int *weed_channel_get_rowstrides(weed_plant_t *channel, int *nplanes);
#endif

/* Threading */
int weed_is_threading(weed_plant_t *inst);
int weed_channel_get_offset(weed_plant_t *channel);
int weed_channel_get_true_height(weed_plant_t *channel);

int IS_THREAD_MASTER(weed_plant_t *inst);
int is_big_endian(void);

ABS(a)

//if defined(NEED_RANDOM)
uint64_t fastrand(uint64_t oldval);

//if defined (NEED_ALPHA_SORT)
typedef struct dlink_list dlink_list_t;
dlink_list_t *add_to_list_sorted(dlink_list_t *list, weed_plant_t *filter, const char *name);
int add_filters_from_list(weed_plant_t *plugin_info, dlink_list_t *list);

//if defined(NEED_PALETTE_UTILS)
#define ALL_RGB_PALETTES
#define ALL_24BIT_PALETTES
#define ALL_32BIT_PALETTES
#define ALL_ALPHA_PALETTES
#define ALL_PACKED_PALETTES
#define ALL_PACKED_PALETTES_PLUS
#define ALL_PLANAR_PALETTES
#define pixel_size(pal)
#define rgb_offset(pal)

int weed_palette_is_alpha(int pal);
int weed_palette_is_rgb(int pal);
int weed_palette_is_yuv(int pal);
int weed_palette_is_float(int pal);
int weed_palette_has_alpha_channel(int pal);
double weed_palette_get_plane_ratio_horizontal(int pal, int plane);
double weed_palette_get_plane_ratio_vertical(int pal, int plane);
int weed_palette_get_nplanes(int pal);
int weed_palette_is_valid(int pal);

size_t blank_pixel(uint8_t *dst, int pal, int yuv_clamping, uint8_t *src);
void blank_row(uint8_t **pdst, int width, int pal, int yuv_clamping, int uvcopy, uint8_t **psrc);

//if defined(NEED_PALETTE_CONVERSIONS)
uint8_t calc_luma(uint8_t *pixel, int palette, int yuv_clamping);
uint8_t y_unclamped_to_clamped(uint8_t y);
uint8_t y_clamped_to_unclamped(uint8_t y);
uint8_t uv_clamped_to_unclamped(uint8_t uv);
/* pre multiply or un-pre-multiply alpha for a frame: if un is set to WEED_TRUE we un-pre-multiply, othewise pre-multiply */
void alpha_premult(unsigned char *ptr, int width, int height, int rowstride, int pal, int un);




Appendix B:

code examples



WRITING A MINIMAL HOST

#include <weed/weed-host.h>
#include <weed/weed.h>
#include <weed/weed-effects.h>

INITIALIZING LIBWEED

simple version:
	if (weed_init(WEED_ABI_VERSION, 0) != WEED_SUCCESS) return;



complete version:
	// if the library weed api is too high, we can lower it
	// this ensures we can use all versions, past and future
	int weed_abi_version = weed_get_abi_version();
	if (weed_abi_version > WEED_ABI_VERSION) weed_abi_version = WEED_ABI_VERSION;

	int flags = 0;

	// if want standard stringfuncs, we can set that; can be useful when debugging with valgrind
	flags |= WEED_INIT_STD_STRINGFUNCS;

	// if we want all possible backported bugfixes, we can allow that, aknowledging the
	// possibility that this will break anything which relied on the buggy behaviour
	flags |= WEED_INIT_ALLBUFIXES;

 	weed_error_t werr = weed_init(weed_abi_version, flags);
	if (werr == WEED_ERROR_BADVERSION) return;



For libweed-utils, we can optionally do:

	// any value can be NULL to use default functions (malloc, free, etc)
  	weed_utils_set_custom_memfuncs(mymalloc, mycalloc, mymemcpy, mymemcp, myfree);




===== OVERLOADING FUNCTIONS FOR THE HOST ====
the following may be useful:

#define WEED_ERROR_NOSUCH_PLANT 65536

== free even 'undeletable' plants ==

static void clear_plant_flags(weed_plant_t *plant) {
  char **leaves = weed_plant_list_leaves(plant, NULL);
  for (int i = 0; leaves[i]; i++) {
    weed_set_int_value(plant, leaves[i], 0);
    free(leaves[i]);
  }
  if (leaves) free(leaves);
}


weed_error_t weed_plant_free_host(weed_plant_t *plant) {
  weed_error_t err;
  if (!plant) return WEED_ERROR_NOSUCH_PLANT;
  err = _weed_plant_free(plant);
  if (err == WEED_ERROR_UNDELETABLE) {
  	clear_plant_flags(plant);
  	return _weed_plant_free(plant);
  }
  return err;
}

then:
weed_plant_free_f _weed_plant_free = weed_plant_free;
weed_plant_free = weed_plant_free_host;

/// the original weed_plant_free should be provided to plugins, e.g. in a host_info_callback (see below)
// weed_set_funcptr_value(host_info, WEED_PLANT_FREE_FUNC, (weed_funcptr_t)_weed_plant_free);



== Delete even 'undeletable' leaves ==

weed_error_t weed_leaf_delete_host(weed_plant_t *plant, const char *key) {
  weed_error_t err;
  if (!plant) return WEED_ERROR_NOSUCH_PLANT;
  err = _weed_leaf_delete(plant, key);
  if (err == WEED_ERROR_UNDELETABLE) {
  	uint32_t flags = weed_leaf_get_flags(plant, key);
  	flags ^= WEED_FLAG_UNDELETABLE;
  	weed_leaf_set_flags(plant, key, flags);
  	err = _weed_leaf_delete(plant, key);
  }
  return err;
}

then:
weed_leaf_delete_f _weed_leaf_delete = weed_leaf_delete;
weed_leaf_delete = weed_leaf_delete_host;

/// the original weed_leaf_delete should be provide to plugins, e.g. in a host_info_callback (see below)
// weed_set_funcptr_value(host_info, WEED_LEAF_DELETE_FUNC, (weed_funcptr_t)_weed_leaf_delete);




== Change even immutable leaves ==

weed_error_t weed_leaf_set_host(weed_plant_t *plant, const char *key, uint32_t seed_type,
	weed_size_t num_elems, void *values) {
  weed_error_t err;
  if (!plant) return WEED_ERROR_NOSUCH_PLANT;
  err = _weed_leaf_set(plant, key, seed_type, num_elems, values);
  if (err == WEED_ERROR_IMMUTABLE) {
    int32_t flags = weed_leaf_get_flags(plant, key);
    flags ^= WEED_FLAG_IMMUTABLE;
    weed_leaf_set_flags(plant, key, flags);
    err = _weed_leaf_set(plant, key, seed_type, num_elems, values);

    // restore original value of flags
    flags |= WEED_FLAG_IMMUTABLE;
    weed_leaf_set_flags(plant, key, flags);
  }
  return err;
}


then:
weed_leaf_set_f _weed_leaf_set = weed_leaf_set;
weed_leaf_set = weed_leaf_set_host;

/// the original weed_leaf_set should be provide to plugins, e.g. in a host_info_callback (see below)
// weed_set_funcptr_value(host_info, WEED_LEAF_SET_FUNC, (weed_funcptr_t)_weed_leaf_set);







LODAING PLUGINS AND FILTERS:
{
	weed_setup_f setup_fn;
	int dlflags = 0; // set with preferred values
	void *handle;

	if ((handle = dlopen(plugin_path, dlflags))) {
		dlerror(); // clear existing errors
	}
	else {
		// handle errors.
	}

	if ((setup_fn = (weed_setup_f)dlsym(handle, "weed_setup")) == NULL) {
		// handle error...
	}

	// optional
	void *data;
	weed_set_host_info_callback(host_info_cb, data);

	// if using libweed_utils, we can pass weed_bootstrap, and host_info_cb will be called
	weed_plant_t *plugin_info = (*setup_fn)(weed_bootstrap);

	// now can parse plugin_info

	int nfilters;
	weed_plant_t **filters;
	filters = weed_get_plantptr_array_counted(plugin_info, WEED_LEAF_FILTERS, &nfilters);
	[libweed-host-utils: filters = weed_get_filters(plugin_info, &nfilters);]

	char *package_name = weed_get_string_value(plugin_info, WEED_LEAF_PACKAGE_NAME, NULL);
	[libweed-host-utils: char *package_name = weed_get_package_name(plugin_info);]


	...

	...

	free(package_name);
	free(filters);
}


HOST_INFO CALLBACK FROM WEED_SETUP (optional, only called if using the default weed_bootstrap):

simple version:

weed_plant_t *host_info_cb(weed_plant_t *host_info, void *data) {
	// any weed functions which were overloaded in the host should be set back
	// to original versions for the plugin:
	weed_set_funcptr_value(host_info, WEED_PLANT_FREE_FUNC, (weed_funcptr_t)_weed_plant_free);


	// the remainder is all optional code, apart from the final return

	weed_set_string_value(host_info, WEED_LEAF_HOST_NAME, "myapp");
	weed_set_string_value(host_info, WEED_LEAF_HOST_VERSION, "myversion");
	weed_set_string_value(host_info, WEED_LEAF_LAYOUT_SCHEMES, "rfx");

	if (DEBUG) weed_set_int_value(host_info, WEED_LEAF_VERBOSITY, WEED_VERBOSITY_DEBUG);
	if (DEBUG) weed_set_int_value(host_info, WEED_LEAF_VERBOSITY, WEED_VERBOSITY_WARN);

	// set as applicable
	weed_set_int_value(host_info, WEED_LEAF_FLAGS, WEED_HOST_SUPPORTS_LINEAR_GAMMA
		     | WEED_HOST_SUPPORTS_PREMULTIPLIED_ALPHA);


	// set any custom values, keys starting with "host_"
	weed_set_string_value(host_info, "host_audio_player", "pulseaudio");

	return host_info;
}



complete version:

weed_plant_t *host_info_cb(weed_plant_t *host_info, void *data) {
	// we can use the host_info created by libweed-utils, or provide our own:
#ifdef USE_OWN_HOST_INFO
	weed_plant_t *our_host_info = weed_plant_new(WEED_PLANT_HOST_INFO);

	// we can use the plugin info created by libweed-utils, or provide our own
	weed_plant_t *plugin_info;
#ifdef USE_SUPPLIED_PINFO
	plugin_info = weed_get_plantptr_value(host_info, WEED_LEAF_PLUGIN_INFO, NULL);
	if (plugin_info) {
		// prevent it from being freed, and reparent it
		weed_set_plantptr_value(host_info, WEED_LEAF_PLUGIN_INFO, NULL);
		weed_set_plantptr_value(our_host_info, WEED_LEAF_PLUGIN_INFO, plugin_info);
	}
#else
	plugin_info = weed_plant_new(WEED_PLANT_PLUGIN_INFO);
	if (!plugin_info) return;
#endif
	weed_set_plantptr_value(our_host_info, WEED_LEAF_PLUGIN_INFO, plugin_info);
	// set mandatory fields for host_info
	...

	...
	// the lib should do this, but it is good practice
	weed_set_plantptr_value(plugin_info, WEED_LEAF_HOST_INFO, our_host_info);

	// set mandatory fields for host_info
	...

	...

	// lib will free original host_info
#endif	



	// version discovery
	// versions used by libweed_utils
	int libweed_version = weed_get_int_value(host_info, WEED_LEAF_WEED_ABI_VERSION, NULL);
	int filter_version = weed_get_int_value(host_info, WEED_LEAF_FILTER_API_VERSION, NULL);

	// versions used by plugin (do NOT change these)
	int plugin_min_weed_version = weed_get_int_value(plugin_info,
		WEED_LEAF_MIN_WEED_ABI_VERSION, NULL);
	int plugin_max_weed_version = weed_get_int_value(plugin_info,
		WEED_LEAF_MIN_WEED_ABI_VERSION, NULL);
	int plugin_min_filter_version = weed_get_int_value(plugin_info,
		WEED_LEAF_MIN_FILTER_API_VERSION, NULL);
	int plugin_max_filter_version = weed_get_int_value(plugin_info,
		WEED_LEAF_MAX_FILTER_API_VERSION, NULL);

	// we can adjust our versions as desired, or to suit the plugin
	weed_set_int_value(host_info, WEED_LEAF_WEED_ABI_VERSION, weed_version);
	weed_set_int_value(host_info, WEED_LEAF_FILTER_API_VERSION, filter_version);

	// on return, the weed-utils library will make sure weed and filter versions are
	// compatible, and set the host version levels in plugin_info to inform the plugin
	// if the versions are incompatible, the plugin will get a NULL plugin info and
	// must exit

	/// overload functions as desired (OPTIONAL)
	weed_set_funcptr_value(host_info, WEED_LEAF_MALLOC_FUNC, (weed_funcptr_t)_ext_malloc);
	weed_set_funcptr_value(host_info, WEED_LEAF_FREE_FUNC, (weed_funcptr_t)_ext_free);
	weed_set_funcptr_value(host_info, WEED_LEAF_REALLOC_FUNC, (weed_funcptr_t)_ext_realloc);
	weed_set_funcptr_value(host_info, WEED_LEAF_CALLOC_FUNC, (weed_funcptr_t)_ext_calloc);
  	weed_set_funcptr_value(host_info, WEED_LEAF_MEMCPY_FUNC, (weed_funcptr_t)_ext_memcmp);
  	weed_set_funcptr_value(host_info, WEED_LEAF_MEMCPY_FUNC, (weed_funcptr_t)_ext_memcpy);
  	weed_set_funcptr_value(host_info, WEED_LEAF_MEMSET_FUNC, (weed_funcptr_t)_ext_memset);
  	weed_set_funcptr_value(host_info, WEED_LEAF_MEMMOVE_FUNC, (weed_funcptr_t)_ext_memmove);

	weed_set_funcptr_value(host_info, WEED_LEAF_SET_FUNC, (weed_funcptr_t)_weed_leaf_set);
	weed_set_funcptr_value(host_info, WEED_LEAF_DELETE_FUNC, (weed_funcptr_t)_weed_leaf_delete);
	weed_set_funcptr_value(host_info, WEED_PLANT_FREE_FUNC, (weed_funcptr_t)_weed_plant_free);

	weed_set_string_value(host_info, WEED_LEAF_HOST_NAME, "myapp");
	weed_set_string_value(host_info, WEED_LEAF_HOST_VERSION, "myversion");
	weed_set_string_value(host_info, WEED_LEAF_LAYOUT_SCHEMES, "rfx");

	if (DEBUG) weed_set_int_value(host_info, WEED_LEAF_VERBOSITY, WEED_VERBOSITY_DEBUG);
	if (DEBUG) weed_set_int_value(host_info, WEED_LEAF_VERBOSITY, WEED_VERBOSITY_WARN);


	// set as applicable
	weed_set_int_value(host_info, WEED_LEAF_FLAGS, WEED_HOST_SUPPORTS_LINEAR_GAMMA
		     | WEED_HOST_SUPPORTS_PREMULTIPLIED_ALPHA);


	// set any custom values, keys starting with "host_"
	weed_set_string_value(host_info, "host_audio_player", "pulseaudio");


	// specific values can be set for a particular plugin using data:

	if (!strcmp(data, "foo")) {
		weed_set_int_value(host_info, WEED_LEAF_VERBOSITY, WEED_VERBOSITY_DEBUG);
	}

	return host_info;
}






CREATING AN INSTANCE FROM A FILTER

weed_plant_t *inst_from_filter(weed_plant_t *filter) {
	int nvals;
	weed_plant_t **in_channels, **out_channels;
	weed_plant_t **in_params, **out_params;

	weed_plant_t *inst = weed_plant_new(WEED_PLANT_FILTER_INSTANCE);
	weed_set_plantptr_value(inst, WEED_LEAF_FILTER_CLASS, filter);

	// RECOMMENDED: to prevent accidental changes by the plugin set all leaves with the flags:
	// WEED_FLAG_IMMUTABLE | WEED_FLAG_UNDELETABLE;

	in_channels = weed_channels_create(filter, 1);
	if (in_channels) {
		weed_set_plantptr_array(inst, WEED_LEAF_IN_CHANNELS, in_channels);
		free(in_channels);
	}

	out_channels = weed_channels_create(filter, 0, &nvals);
	if (out_channels) {
		weed_set_plantptr_array(inst, WEED_LEAF_OUT_CHANNELS, nvals, out_channels);
		free(out_channels);
	}

	in_params = weed_params_create(filter, 1, &nvals);
	if (in_params) {
		weed_set_plantptr_array(inst, WEED_LEAF_IN_PARAMS, nvals, in_params);
		free(in_params);
	}

	out_params = weed_params_create(filter, 0, &nvals);
	if (out_params) {
		weed_set_plantptr_array(inst, WEED_LEAF_OUT_PARAMS, nvals, out_params);
		free(out_params);
	}

	return inst;
}

[libweed-host-utils: weed_plant_t *inst = weed_instance_new_from_filter(filter);]




CREATING CHANNELS


weed_plant_t **weed_channels_create(weed_plant_t *filter, int in, int *nvals) {
	// set in to 1 to create in_channels, 0 for out_channels

	weed_plant_t **chantmpls, **channels;
	int num_channels, num_repeats, ccount = 0;
	int i, j;

	if (in) chantmpls = weed_get_plantptr_array_counted(filter,
		WEED_LEAF_IN_CHANNEL_TEMPLATES, &num_channels);
	else chantmpls = weed_get_plantptr_array_counted(filter,
		WEED_LEAF_OUT_CHANNEL_TEMPLATES, &num_channels);

[libweed-host-utils:
	if (in) chantmpls = weed_filter_get_in_chantmpls(filter, &num_channels);
	else chantmpls = weed_filter_get_out_chantmpls(filter, &num_channels);
]

	for (i = 0; i < num_channels; i++) {
		if (weed_plant_has_leaf(chantmpls[i], WEED_LEAF_HOST_REPEATS))
		ccount += weed_get_int_value(chantmpls[i], WEED_LEAF_HOST_REPEATS, NULL);
		else ccount += 1;
	}

[libweed-host-utils:
	for (i = 0; i < num_channels; i++) {
		ccount += weed_chantmpl_get_max_repeats(chantmpls[i]);
	}
]

	// create a channel for each template, including repeats
	channels = (weed_plant_t **)calloc((ccount + 1), sizeof(weed_plant_t *));

	ccount = 0;

	for (i = 0; i < num_channels; i++) {
		num_repeats = weed_get_int_value(chantmpls[i], WEED_LEAF_HOST_REPEATS, NULL);
    		if (!num_repeats) num_repeats = 1;
[libweed-host-utils:
		num_repeats = weed_chantmpl_get_max_repeats(chantmpls[i]);
]
    		for (j = 0; j < num_repeats; j++) {
      			channels[ccount] = weed_plant_new(WEED_PLANT_CHANNEL);
      			weed_set_plantptr_value(channels[ccount], WEED_LEAF_TEMPLATE,
					chantmpls[i]);

			/// set defaults if desired....
			if (!weed_get_boolean_value(chantmpls[i], WEED_LEAF_IS_AUDIO, NULL)) {
[libweed-host-utils:
			if (!weed_chantmpl_is_audio(chantmpls[i])) {
]
				// set defaults for video
			}
			else {
				// set defaults for audio
			}
		ccount++;
		}
	}

  	free(chantmpls);
	if (nvals) *nvals = ccount;
  	return channels;
}


CREATING PARAMETERS

TODO



CONFIGURING AN INSTANCE

Before calling init_func or process_func, the instance needs to be configured for the filter.

This can be done in steps:

- enable / disable optional channels

- set sizes / palettes for enabled channels

- set in_parameter values

this may require a reinit of the instance, so we need to check for this.

We can then call the init_func or the process_func as reqired.


TODO



CALLING INIT_FUNC
Once an instance configured we can call the init_func for the filter. If such a function
exists, it needs to be done exactly once* before we can call the process_func

(*An exception exists for a special kind of init called a GUI init, this will be explained below).


Any errors returned from the init_func need to be handled by the host.


TODO




CALLING PROCESS_FUNC
Once the instance is configured, and the init_func called, the process_func may then be called as
often as required.

Some configuration changes require a re-init before calling the process_func.

After the process_func returns, we need to handle any errors returned.


We can then make use of the out_channels and out_parameters set by the filter.


TODO



CALLING DEINIT_FUNC
The deinit_func should be called if the instance needs resetting, if a reinit is required due to
error conditions or configuration changes in the instance, or
before unloading the plugin. If the plugin has an init_func, then that function must have been
called on the instance, before deinit_func can be called.

If the filter has an init_func, then fter calling deinit_func, the init_func must be called again
before the process_func can be used, or before deinit_func can be called again.


TODO



UNLOADING A PLUGIN


TODO




OPTIONAL ADVANCED FEATURES

